Merge branches 'acpi-video' and 'acpi-pmic'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 8 Dec 2014 18:54:45 +0000 (19:54 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 8 Dec 2014 18:54:45 +0000 (19:54 +0100)
* acpi-video:
  ACPI / video: Run _BCL before deciding registering backlight

* acpi-pmic:
  ACPI / PMIC: AXP288: support virtual GPIO in ACPI table
  ACPI / PMIC: support PMIC operation region for XPower AXP288
  ACPI / PMIC: support PMIC operation region for CrystalCove
  iio/axp288_adc: remove THIS_MODULE owner
  mfd/axp20x: avoid irq numbering collision
  iio: adc: Add module device table for autoloading
  iio: adc: Add support for axp288 adc
  mfd: axp20x: Extend axp20x to support axp288 pmic

123 files changed:
Documentation/acpi/gpio-properties.txt [new file with mode: 0644]
Documentation/gpio/consumer.txt
MAINTAINERS
Makefile
arch/arm/mach-s3c24xx/h1940-bluetooth.c
arch/arm/mach-s3c24xx/h1940.h
arch/arm/mach-s3c24xx/mach-h1940.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/plat-orion/gpio.c
arch/arm/plat-orion/include/plat/orion-gpio.h
arch/s390/kernel/nmi.c
arch/x86/boot/compressed/Makefile
arch/x86/kernel/cpu/microcode/core.c
block/bio-integrity.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_lpss.c
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/utresrc.c
drivers/acpi/acpica/utxface.c
drivers/acpi/acpica/utxfinit.c
drivers/acpi/battery.c
drivers/acpi/device_pm.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pmic/intel_pmic.c [new file with mode: 0644]
drivers/acpi/pmic/intel_pmic.h [new file with mode: 0644]
drivers/acpi/pmic/intel_pmic_crc.c [new file with mode: 0644]
drivers/acpi/pmic/intel_pmic_xpower.c [new file with mode: 0644]
drivers/acpi/processor_idle.c
drivers/acpi/property.c [new file with mode: 0644]
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/tables.c
drivers/acpi/utils.c
drivers/ata/ahci.c
drivers/ata/sata_fsl.c
drivers/base/Makefile
drivers/base/property.c [new file with mode: 0644]
drivers/dma/dw/core.c
drivers/gpio/devres.c
drivers/gpio/gpio-sch.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/i2c-core.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/axp288_adc.c [new file with mode: 0644]
drivers/input/evdev.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/leds/leds-gpio.c
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/solo6x10/solo6x10-core.c
drivers/media/rc/ir-rc6-decoder.c
drivers/media/usb/s2255/s2255drv.c
drivers/mfd/Kconfig
drivers/mfd/axp20x.c
drivers/mfd/intel_soc_pmic_crc.c
drivers/misc/eeprom/at25.c
drivers/net/bonding/bond_netlink.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/xen-netfront.c
drivers/of/base.c
drivers/of/fdt.c
drivers/pci/host/pci-tegra.c
drivers/watchdog/s3c2410_wdt.c
fs/fat/namei_vfat.c
fs/jbd2/journal.c
include/acpi/acbuffer.h
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/actypes.h
include/acpi/processor.h
include/linux/acpi.h
include/linux/gpio/consumer.h
include/linux/gpio_keys.h
include/linux/leds.h
include/linux/mfd/axp20x.h
include/linux/of.h
include/linux/property.h [new file with mode: 0644]
include/uapi/linux/Kbuild
ipc/sem.c
kernel/sched/core.c
lib/genalloc.c
lib/show_mem.c
mm/frontswap.c
mm/memory.c
mm/mmap.c
mm/rmap.c
mm/slab.c
mm/vmpressure.c
net/core/rtnetlink.c
net/rfkill/rfkill-gpio.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/keyring.c
security/keys/request_key.c
security/keys/request_key_auth.c
sound/pci/hda/patch_realtek.c

diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt
new file mode 100644 (file)
index 0000000..ae36fcf
--- /dev/null
@@ -0,0 +1,96 @@
+_DSD Device Properties Related to GPIO
+--------------------------------------
+
+With the release of ACPI 5.1 and the _DSD configuration objecte names
+can finally be given to GPIOs (and other things as well) returned by
+_CRS.  Previously, we were only able to use an integer index to find
+the corresponding GPIO, which is pretty error prone (it depends on
+the _CRS output ordering, for example).
+
+With _DSD we can now query GPIOs using a name instead of an integer
+index, like the ASL example below shows:
+
+  // Bluetooth device with reset and shutdown GPIOs
+  Device (BTH)
+  {
+      Name (_HID, ...)
+
+      Name (_CRS, ResourceTemplate ()
+      {
+          GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+                  "\\_SB.GPO0", 0, ResourceConsumer) {15}
+          GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+                  "\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
+      })
+
+      Name (_DSD, Package ()
+      {
+          ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+          Package ()
+         {
+              Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
+              Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
+          }
+      })
+  }
+
+The format of the supported GPIO property is:
+
+  Package () { "name", Package () { ref, index, pin, active_low }}
+
+  ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
+        typically this is the device itself (BTH in our case).
+  index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
+  pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
+  active_low - If 1 the GPIO is marked as active_low.
+
+Since ACPI GpioIo() resource does not have a field saying whether it is
+active low or high, the "active_low" argument can be used here.  Setting
+it to 1 marks the GPIO as active low.
+
+In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
+resource, second pin in that resource with the GPIO number of 31.
+
+ACPI GPIO Mappings Provided by Drivers
+--------------------------------------
+
+There are systems in which the ACPI tables do not contain _DSD but provide _CRS
+with GpioIo()/GpioInt() resources and device drivers still need to work with
+them.
+
+In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
+available to the driver can be used to identify the device and that is supposed
+to be sufficient to determine the meaning and purpose of all of the GPIO lines
+listed by the GpioIo()/GpioInt() resources returned by _CRS.  In other words,
+the driver is supposed to know what to use the GpioIo()/GpioInt() resources for
+once it has identified the device.  Having done that, it can simply assign names
+to the GPIO lines it is going to use and provide the GPIO subsystem with a
+mapping between those names and the ACPI GPIO resources corresponding to them.
+
+To do that, the driver needs to define a mapping table as a NULL-terminated
+array of struct acpi_gpio_mapping objects that each contain a name, a pointer
+to an array of line data (struct acpi_gpio_params) objects and the size of that
+array.  Each struct acpi_gpio_params object consists of three fields,
+crs_entry_index, line_index, active_low, representing the index of the target
+GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
+line in that resource starting from zero, and the active-low flag for that line,
+respectively, in analogy with the _DSD GPIO property format specified above.
+
+For the example Bluetooth device discussed previously the data structures in
+question would look like this:
+
+static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
+static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
+
+static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
+  { "reset-gpio", &reset_gpio, 1 },
+  { "shutdown-gpio", &shutdown_gpio, 1 },
+  { },
+};
+
+Next, the mapping table needs to be passed as the second argument to
+acpi_dev_add_driver_gpios() that will register it with the ACPI device object
+pointed to by its first argument.  That should be done in the driver's .probe()
+routine.  On removal, the driver should unregister its GPIO mapping table by
+calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
+table was previously registered.
index 6ce5441..859918d 100644 (file)
@@ -219,6 +219,24 @@ part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup
 capabilities.
 
 
+GPIOs and ACPI
+==============
+
+On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by
+the _CRS configuration objects of devices.  Those resources do not provide
+connection IDs (names) for GPIOs, so it is necessary to use an additional
+mechanism for this purpose.
+
+Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object
+which, among other things, may be used to provide connection IDs for specific
+GPIOs described by the GpioIo()/GpioInt() resources in _CRS.  If that is the
+case, it will be handled by the GPIO subsystem automatically.  However, if the
+_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO
+connection IDs need to be provided by device drivers.
+
+For details refer to Documentation/acpi/gpio-properties.txt
+
+
 Interacting With the Legacy GPIO Subsystem
 ==========================================
 Many kernel subsystems still handle GPIOs using the legacy integer-based
index 0ff630d..c721042 100644 (file)
@@ -1828,7 +1828,7 @@ F:        include/net/ax25.h
 F:     net/ax25/
 
 AZ6007 DVB DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -2198,7 +2198,7 @@ F:        Documentation/filesystems/btrfs.txt
 F:     fs/btrfs/
 
 BTTV VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -2719,7 +2719,7 @@ F:        drivers/media/common/cx2341x*
 F:     include/media/cx2341x*
 
 CX88 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -3402,7 +3402,7 @@ F:        fs/ecryptfs/
 EDAC-CORE
 M:     Doug Thompson <dougthompson@xmission.com>
 M:     Borislav Petkov <bp@alien8.de>
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Supported
@@ -3451,7 +3451,7 @@ S:        Maintained
 F:     drivers/edac/e7xxx_edac.c
 
 EDAC-GHES
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -3479,21 +3479,21 @@ 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>
 L:     linux-edac@vger.kernel.org
 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>
 L:     linux-edac@vger.kernel.org
 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>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -3536,7 +3536,7 @@ 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>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
@@ -3596,7 +3596,7 @@ 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>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -5962,7 +5962,7 @@ S:        Maintained
 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
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
@@ -8013,7 +8013,7 @@ S:        Odd Fixes
 F:     drivers/media/i2c/saa6588*
 
 SAA7134 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -8471,7 +8471,7 @@ S:        Maintained
 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>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -8682,7 +8682,9 @@ S:        Maintained
 F:     drivers/leds/leds-net48xx.c
 
 SOFTLOGIC 6x10 MPEG CODEC
-M:     Ismael Luceno <ismael.luceno@corp.bluecherry.net>
+M:     Bluecherry Maintainers <maintainers@bluecherrydvr.com>
+M:     Andrey Utkin <andrey.utkin@corp.bluecherry.net>
+M:     Andrey Utkin <andrey.krieger.utkin@gmail.com>
 L:     linux-media@vger.kernel.org
 S:     Supported
 F:     drivers/media/pci/solo6x10/
@@ -9156,7 +9158,7 @@ S:        Maintained
 F:     drivers/media/i2c/tda9840*
 
 TEA5761 TUNER DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -9164,7 +9166,7 @@ S:        Odd fixes
 F:     drivers/media/tuners/tea5761.*
 
 TEA5767 TUNER DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -9476,7 +9478,7 @@ F:        include/linux/shmem_fs.h
 F:     mm/shmem.c
 
 TM6000 VIDEO4LINUX DRIVER
-M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
+M:     Mauro Carvalho Chehab <mchehab@osg.samsung.com>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
@@ -10297,7 +10299,7 @@ S:      Maintained
 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>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
index ce70361..fd80c6e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 18
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Diseased Newt
 
 # *DOCUMENTATION*
index b4d14b8..9c8b127 100644 (file)
@@ -41,7 +41,7 @@ static void h1940bt_enable(int on)
                mdelay(10);
                gpio_set_value(S3C2410_GPH(1), 0);
 
-               h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
+               h1940_led_blink_set(NULL, GPIO_LED_BLINK, NULL, NULL);
        }
        else {
                gpio_set_value(S3C2410_GPH(1), 1);
@@ -50,7 +50,7 @@ static void h1940bt_enable(int on)
                mdelay(10);
                gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
 
-               h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
+               h1940_led_blink_set(NULL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
        }
 }
 
index 2950cc4..596d9f6 100644 (file)
 #define H1940_SUSPEND_RESUMEAT         (0x30081000)
 #define H1940_SUSPEND_CHECK            (0x30080000)
 
+struct gpio_desc;
+
 extern void h1940_pm_return(void);
-extern int h1940_led_blink_set(unsigned gpio, int state,
+extern int h1940_led_blink_set(struct gpio_desc *desc, int state,
                               unsigned long *delay_on,
                               unsigned long *delay_off);
 
index d35ddc1..d40d4f5 100644 (file)
@@ -359,10 +359,11 @@ static struct platform_device h1940_battery = {
 
 static DEFINE_SPINLOCK(h1940_blink_spin);
 
-int h1940_led_blink_set(unsigned gpio, int state,
+int h1940_led_blink_set(struct gpio_desc *desc, int state,
        unsigned long *delay_on, unsigned long *delay_off)
 {
        int blink_gpio, check_gpio1, check_gpio2;
+       int gpio = desc ? desc_to_gpio(desc) : -EINVAL;
 
        switch (gpio) {
        case H1940_LATCH_LED_GREEN:
index c3f2682..1d35ff3 100644 (file)
@@ -250,9 +250,10 @@ static void rx1950_disable_charger(void)
 
 static DEFINE_SPINLOCK(rx1950_blink_spin);
 
-static int rx1950_led_blink_set(unsigned gpio, int state,
+static int rx1950_led_blink_set(struct gpio_desc *desc, int state,
        unsigned long *delay_on, unsigned long *delay_off)
 {
+       int gpio = desc_to_gpio(desc);
        int blink_gpio, check_gpio;
 
        switch (gpio) {
index e048f61..e53fc8d 100644 (file)
@@ -306,9 +306,10 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
 
 #define ORION_BLINK_HALF_PERIOD 100 /* ms */
 
-int orion_gpio_led_blink_set(unsigned gpio, int state,
+int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
        unsigned long *delay_on, unsigned long *delay_off)
 {
+       unsigned gpio = desc_to_gpio(desc);
 
        if (delay_on && delay_off && !*delay_on && !*delay_off)
                *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
index e763988..e856b07 100644 (file)
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/irqdomain.h>
+
+struct gpio_desc;
+
 /*
  * Orion-specific GPIO API extensions.
  */
 void orion_gpio_set_unused(unsigned pin);
 void orion_gpio_set_blink(unsigned pin, int blink);
-int orion_gpio_led_blink_set(unsigned gpio, int state,
+int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
        unsigned long *delay_on, unsigned long *delay_off);
 
 #define GPIO_INPUT_OK          (1 << 0)
index dd1c24c..3f51cf4 100644 (file)
@@ -54,12 +54,8 @@ void s390_handle_mcck(void)
         */
        local_irq_save(flags);
        local_mcck_disable();
-       /*
-        * Ummm... Does this make sense at all? Copying the percpu struct
-        * and then zapping it one statement later?
-        */
-       memcpy(&mcck, this_cpu_ptr(&cpu_mcck), sizeof(mcck));
-       memset(&mcck, 0, sizeof(struct mcck_struct));
+       mcck = *this_cpu_ptr(&cpu_mcck);
+       memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck));
        clear_cpu_flag(CIF_MCCK_PENDING);
        local_mcck_enable();
        local_irq_restore(flags);
index be1e07d..45abc36 100644 (file)
@@ -76,7 +76,7 @@ suffix-$(CONFIG_KERNEL_XZ)    := xz
 suffix-$(CONFIG_KERNEL_LZO)    := lzo
 suffix-$(CONFIG_KERNEL_LZ4)    := lz4
 
-RUN_SIZE = $(shell objdump -h vmlinux | \
+RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \
             perl $(srctree)/arch/x86/tools/calc_run_size.pl)
 quiet_cmd_mkpiggy = MKPIGGY $@
       cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
index 2ce9051..08fe6e8 100644 (file)
@@ -465,6 +465,7 @@ static void mc_bp_resume(void)
 
        if (uci->valid && uci->mc)
                microcode_ops->apply_microcode(cpu);
+#ifdef CONFIG_X86_64
        else if (!uci->mc)
                /*
                 * We might resume and not have applied late microcode but still
@@ -473,6 +474,7 @@ static void mc_bp_resume(void)
                 * applying patches early on the APs.
                 */
                load_ucode_ap();
+#endif
 }
 
 static struct syscore_ops mc_syscore_ops = {
index 0984232..5cbd5d9 100644 (file)
@@ -216,9 +216,10 @@ static int bio_integrity_process(struct bio *bio,
 {
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
        struct blk_integrity_iter iter;
-       struct bio_vec *bv;
+       struct bvec_iter bviter;
+       struct bio_vec bv;
        struct bio_integrity_payload *bip = bio_integrity(bio);
-       unsigned int i, ret = 0;
+       unsigned int ret = 0;
        void *prot_buf = page_address(bip->bip_vec->bv_page) +
                bip->bip_vec->bv_offset;
 
@@ -227,11 +228,11 @@ static int bio_integrity_process(struct bio *bio,
        iter.seed = bip_get_seed(bip);
        iter.prot_buf = prot_buf;
 
-       bio_for_each_segment_all(bv, bio, i) {
-               void *kaddr = kmap_atomic(bv->bv_page);
+       bio_for_each_segment(bv, bio, bviter) {
+               void *kaddr = kmap_atomic(bv.bv_page);
 
-               iter.data_buf = kaddr + bv->bv_offset;
-               iter.data_size = bv->bv_len;
+               iter.data_buf = kaddr + bv.bv_offset;
+               iter.data_size = bv.bv_len;
 
                ret = proc_fn(&iter);
                if (ret) {
index b23fe37..8951cef 100644 (file)
@@ -360,15 +360,14 @@ config ACPI_BGRT
 config ACPI_REDUCED_HARDWARE_ONLY
        bool "Hardware-reduced ACPI support only" if EXPERT
        def_bool n
-       depends on ACPI
        help
-       This config item changes the way the ACPI code is built.  When this
-       option is selected, the kernel will use a specialized version of
-       ACPICA that ONLY supports the ACPI "reduced hardware" mode.  The
-       resulting kernel will be smaller but it will also be restricted to
-       running in ACPI reduced hardware mode ONLY.
+         This config item changes the way the ACPI code is built.  When this
+         option is selected, the kernel will use a specialized version of
+         ACPICA that ONLY supports the ACPI "reduced hardware" mode.  The
+         resulting kernel will be smaller but it will also be restricted to
+         running in ACPI reduced hardware mode ONLY.
 
-       If you are unsure what to do, do not enable this option.
+         If you are unsure what to do, do not enable this option.
 
 source "drivers/acpi/apei/Kconfig"
 
@@ -394,4 +393,27 @@ config ACPI_EXTLOG
          driver adds support for that functionality with corresponding
          tracepoint which carries that information to userspace.
 
+menuconfig PMIC_OPREGION
+       bool "PMIC (Power Management Integrated Circuit) operation region support"
+       help
+         Select this option to enable support for ACPI operation
+         region of the PMIC chip. The operation region can be used
+         to control power rails and sensor reading/writing on the
+         PMIC chip.
+
+if PMIC_OPREGION
+config CRC_PMIC_OPREGION
+       bool "ACPI operation region support for CrystalCove PMIC"
+       depends on INTEL_SOC_PMIC
+       help
+         This config adds ACPI operation region support for CrystalCove PMIC.
+
+config XPOWER_PMIC_OPREGION
+       bool "ACPI operation region support for XPower AXP288 PMIC"
+       depends on AXP288_ADC = y
+       help
+         This config adds ACPI operation region support for XPower AXP288 PMIC.
+
+endif
+
 endif  # ACPI
index c3b2fcb..f74317c 100644 (file)
@@ -47,6 +47,7 @@ acpi-y                                += int340x_thermal.o
 acpi-y                         += power.o
 acpi-y                         += event.o
 acpi-y                         += sysfs.o
+acpi-y                         += property.o
 acpi-$(CONFIG_X86)             += acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)                += debugfs.o
 acpi-$(CONFIG_ACPI_NUMA)       += numa.o
@@ -87,3 +88,7 @@ obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
 obj-$(CONFIG_ACPI_APEI)                += apei/
 
 obj-$(CONFIG_ACPI_EXTLOG)      += acpi_extlog.o
+
+obj-$(CONFIG_PMIC_OPREGION)    += pmic/intel_pmic.o
+obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
+obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
index 93d1606..d1dd0ad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ACPI support for Intel Lynxpoint LPSS.
  *
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2014, Intel Corporation
  * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
  *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
@@ -60,6 +60,8 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_CLK_DIVIDER               BIT(2)
 #define LPSS_LTR                       BIT(3)
 #define LPSS_SAVE_CTX                  BIT(4)
+#define LPSS_DEV_PROXY                 BIT(5)
+#define LPSS_PROXY_REQ                 BIT(6)
 
 struct lpss_private_data;
 
@@ -70,8 +72,10 @@ struct lpss_device_desc {
        void (*setup)(struct lpss_private_data *pdata);
 };
 
+static struct device *proxy_device;
+
 static struct lpss_device_desc lpss_dma_desc = {
-       .flags = LPSS_CLK,
+       .flags = LPSS_CLK | LPSS_PROXY_REQ,
 };
 
 struct lpss_private_data {
@@ -146,22 +150,24 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
 };
 
 static struct lpss_device_desc byt_uart_dev_desc = {
-       .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+       .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+                LPSS_DEV_PROXY,
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
 
 static struct lpss_device_desc byt_spi_dev_desc = {
-       .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+       .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+                LPSS_DEV_PROXY,
        .prv_offset = 0x400,
 };
 
 static struct lpss_device_desc byt_sdio_dev_desc = {
-       .flags = LPSS_CLK,
+       .flags = LPSS_CLK | LPSS_DEV_PROXY,
 };
 
 static struct lpss_device_desc byt_i2c_dev_desc = {
-       .flags = LPSS_CLK | LPSS_SAVE_CTX,
+       .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY,
        .prv_offset = 0x800,
        .setup = byt_i2c_setup,
 };
@@ -368,6 +374,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
        adev->driver_data = pdata;
        pdev = acpi_create_platform_device(adev);
        if (!IS_ERR_OR_NULL(pdev)) {
+               if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY)
+                       proxy_device = &pdev->dev;
                return 1;
        }
 
@@ -499,14 +507,15 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
 /**
  * acpi_lpss_save_ctx() - Save the private registers of LPSS device
  * @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
  *
  * Most LPSS devices have private registers which may loose their context when
  * the device is powered down. acpi_lpss_save_ctx() saves those registers into
  * prv_reg_ctx array.
  */
-static void acpi_lpss_save_ctx(struct device *dev)
+static void acpi_lpss_save_ctx(struct device *dev,
+                              struct lpss_private_data *pdata)
 {
-       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
        unsigned int i;
 
        for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
@@ -521,12 +530,13 @@ static void acpi_lpss_save_ctx(struct device *dev)
 /**
  * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
  * @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
  *
  * Restores the registers that were previously stored with acpi_lpss_save_ctx().
  */
-static void acpi_lpss_restore_ctx(struct device *dev)
+static void acpi_lpss_restore_ctx(struct device *dev,
+                                 struct lpss_private_data *pdata)
 {
-       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
        unsigned int i;
 
        /*
@@ -549,23 +559,31 @@ static void acpi_lpss_restore_ctx(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int acpi_lpss_suspend_late(struct device *dev)
 {
-       int ret = pm_generic_suspend_late(dev);
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+       int ret;
 
+       ret = pm_generic_suspend_late(dev);
        if (ret)
                return ret;
 
-       acpi_lpss_save_ctx(dev);
+       if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+               acpi_lpss_save_ctx(dev, pdata);
+
        return acpi_dev_suspend_late(dev);
 }
 
 static int acpi_lpss_resume_early(struct device *dev)
 {
-       int ret = acpi_dev_resume_early(dev);
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+       int ret;
 
+       ret = acpi_dev_resume_early(dev);
        if (ret)
                return ret;
 
-       acpi_lpss_restore_ctx(dev);
+       if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+               acpi_lpss_restore_ctx(dev, pdata);
+
        return pm_generic_resume_early(dev);
 }
 #endif /* CONFIG_PM_SLEEP */
@@ -573,23 +591,44 @@ static int acpi_lpss_resume_early(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int acpi_lpss_runtime_suspend(struct device *dev)
 {
-       int ret = pm_generic_runtime_suspend(dev);
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+       int ret;
 
+       ret = pm_generic_runtime_suspend(dev);
        if (ret)
                return ret;
 
-       acpi_lpss_save_ctx(dev);
-       return acpi_dev_runtime_suspend(dev);
+       if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+               acpi_lpss_save_ctx(dev, pdata);
+
+       ret = acpi_dev_runtime_suspend(dev);
+       if (ret)
+               return ret;
+
+       if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device)
+               return pm_runtime_put_sync_suspend(proxy_device);
+
+       return 0;
 }
 
 static int acpi_lpss_runtime_resume(struct device *dev)
 {
-       int ret = acpi_dev_runtime_resume(dev);
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+       int ret;
+
+       if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) {
+               ret = pm_runtime_get_sync(proxy_device);
+               if (ret)
+                       return ret;
+       }
 
+       ret = acpi_dev_runtime_resume(dev);
        if (ret)
                return ret;
 
-       acpi_lpss_restore_ctx(dev);
+       if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+               acpi_lpss_restore_ctx(dev, pdata);
+
        return pm_generic_runtime_resume(dev);
 }
 #endif /* CONFIG_PM_RUNTIME */
@@ -631,30 +670,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
                return 0;
 
        pdata = acpi_driver_data(adev);
-       if (!pdata || !pdata->mmio_base)
+       if (!pdata)
                return 0;
 
-       if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
+       if (pdata->mmio_base &&
+           pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
                dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
                return 0;
        }
 
        switch (action) {
-       case BUS_NOTIFY_BOUND_DRIVER:
-               if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
-                       pdev->dev.pm_domain = &acpi_lpss_pm_domain;
-               break;
-       case BUS_NOTIFY_UNBOUND_DRIVER:
-               if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
-                       pdev->dev.pm_domain = NULL;
-               break;
        case BUS_NOTIFY_ADD_DEVICE:
+               pdev->dev.pm_domain = &acpi_lpss_pm_domain;
                if (pdata->dev_desc->flags & LPSS_LTR)
                        return sysfs_create_group(&pdev->dev.kobj,
                                                  &lpss_attr_group);
+               break;
        case BUS_NOTIFY_DEL_DEVICE:
                if (pdata->dev_desc->flags & LPSS_LTR)
                        sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+               pdev->dev.pm_domain = NULL;
+               break;
        default:
                break;
        }
index ebf02cc..7f60582 100644 (file)
@@ -305,6 +305,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_db_output_flags, ACPI_DB_CONSOLE_OUTPUT);
 
 ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE);
 
 ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
 ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
index c00e7e4..680d23b 100644 (file)
@@ -454,6 +454,7 @@ struct acpi_gpe_register_info {
        u16 base_gpe_number;    /* Base GPE number for this register */
        u8 enable_for_wake;     /* GPEs to keep enabled when sleeping */
        u8 enable_for_run;      /* GPEs to keep enabled when running */
+       u8 enable_mask;         /* Current mask of enabled GPEs */
 };
 
 /*
@@ -722,6 +723,7 @@ union acpi_parse_value {
        ACPI_DISASM_ONLY_MEMBERS (\
        u8                              disasm_flags;   /* Used during AML disassembly */\
        u8                              disasm_opcode;  /* Subtype used for disassembly */\
+       char                            *operator_symbol;/* Used for C-style operator name strings */\
        char                            aml_op_name[16])        /* Op name (debug only) */
 
 /* Flags for disasm_flags field above */
@@ -827,6 +829,8 @@ struct acpi_parse_state {
 #define ACPI_PARSEOP_EMPTY_TERMLIST     0x04
 #define ACPI_PARSEOP_PREDEF_CHECKED     0x08
 #define ACPI_PARSEOP_SPECIAL            0x10
+#define ACPI_PARSEOP_COMPOUND           0x20
+#define ACPI_PARSEOP_ASSIGNMENT         0x40
 
 /*****************************************************************************
  *
index 2095dfb..aa70154 100644 (file)
@@ -134,7 +134,7 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
 
        /* Enable the requested GPE */
 
-       status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+       status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE_SAVE);
        return_ACPI_STATUS(status);
 }
 
@@ -213,7 +213,7 @@ acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
                if (ACPI_SUCCESS(status)) {
                        status =
                            acpi_hw_low_set_gpe(gpe_event_info,
-                                               ACPI_GPE_DISABLE);
+                                               ACPI_GPE_DISABLE_SAVE);
                }
 
                if (ACPI_FAILURE(status)) {
@@ -616,8 +616,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
 static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
 {
        struct acpi_gpe_event_info *gpe_event_info = context;
+       acpi_cpu_flags flags;
 
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
        (void)acpi_ev_finish_gpe(gpe_event_info);
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
        ACPI_FREE(gpe_event_info);
        return;
@@ -655,7 +658,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
 
        /*
         * Enable this GPE, conditionally. This means that the GPE will
-        * only be physically enabled if the enable_for_run bit is set
+        * only be physically enabled if the enable_mask bit is set
         * in the event_info.
         */
        (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
index 48ac7b7..494027f 100644 (file)
@@ -115,12 +115,12 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
        /* Set or clear just the bit that corresponds to this GPE */
 
        register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
-       switch (action) {
+       switch (action & ~ACPI_GPE_SAVE_MASK) {
        case ACPI_GPE_CONDITIONAL_ENABLE:
 
-               /* Only enable if the enable_for_run bit is set */
+               /* Only enable if the corresponding enable_mask bit is set */
 
-               if (!(register_bit & gpe_register_info->enable_for_run)) {
+               if (!(register_bit & gpe_register_info->enable_mask)) {
                        return (AE_BAD_PARAMETER);
                }
 
@@ -145,6 +145,9 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
        /* Write the updated enable mask */
 
        status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+       if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) {
+               gpe_register_info->enable_mask = enable_mask;
+       }
        return (status);
 }
 
@@ -260,6 +263,32 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
        return (AE_OK);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_gpe_enable_write
+ *
+ * PARAMETERS:  enable_mask         - Bit mask to write to the GPE register
+ *              gpe_register_info   - Gpe Register info
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Write the enable mask byte to the given GPE register.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_gpe_enable_write(u8 enable_mask,
+                        struct acpi_gpe_register_info *gpe_register_info)
+{
+       acpi_status status;
+
+       status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+       if (ACPI_SUCCESS(status)) {
+               gpe_register_info->enable_mask = enable_mask;
+       }
+       return (status);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_disable_gpe_block
@@ -287,8 +316,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                /* Disable all GPEs in this register */
 
                status =
-                   acpi_hw_write(0x00,
-                                 &gpe_block->register_info[i].enable_address);
+                   acpi_hw_gpe_enable_write(0x00,
+                                            &gpe_block->register_info[i]);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
@@ -355,21 +384,23 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 {
        u32 i;
        acpi_status status;
+       struct acpi_gpe_register_info *gpe_register_info;
 
        /* NOTE: assumes that all GPEs are currently disabled */
 
        /* Examine each GPE Register within the block */
 
        for (i = 0; i < gpe_block->register_count; i++) {
-               if (!gpe_block->register_info[i].enable_for_run) {
+               gpe_register_info = &gpe_block->register_info[i];
+               if (!gpe_register_info->enable_for_run) {
                        continue;
                }
 
                /* Enable all "runtime" GPEs in this register */
 
                status =
-                   acpi_hw_write(gpe_block->register_info[i].enable_for_run,
-                                 &gpe_block->register_info[i].enable_address);
+                   acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run,
+                                            gpe_register_info);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
@@ -399,10 +430,12 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 {
        u32 i;
        acpi_status status;
+       struct acpi_gpe_register_info *gpe_register_info;
 
        /* Examine each GPE Register within the block */
 
        for (i = 0; i < gpe_block->register_count; i++) {
+               gpe_register_info = &gpe_block->register_info[i];
 
                /*
                 * Enable all "wake" GPEs in this register and disable the
@@ -410,8 +443,8 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                 */
 
                status =
-                   acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
-                                 &gpe_block->register_info[i].enable_address);
+                   acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake,
+                                            gpe_register_info);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
index 5cd017c..bc1ff82 100644 (file)
@@ -263,7 +263,7 @@ const char *acpi_gbl_bpb_decode[] = {
 /* UART serial bus stop bits */
 
 const char *acpi_gbl_sb_decode[] = {
-       "StopBitsNone",
+       "StopBitsZero",
        "StopBitsOne",
        "StopBitsOnePlusHalf",
        "StopBitsTwo"
index 502a849..49c873c 100644 (file)
@@ -531,7 +531,9 @@ acpi_decode_pld_buffer(u8 *in_buffer,
        ACPI_MOVE_32_TO_32(&dword, &buffer[0]);
        pld_info->revision = ACPI_PLD_GET_REVISION(&dword);
        pld_info->ignore_color = ACPI_PLD_GET_IGNORE_COLOR(&dword);
-       pld_info->color = ACPI_PLD_GET_COLOR(&dword);
+       pld_info->red = ACPI_PLD_GET_RED(&dword);
+       pld_info->green = ACPI_PLD_GET_GREEN(&dword);
+       pld_info->blue = ACPI_PLD_GET_BLUE(&dword);
 
        /* Second 32-bit DWord */
 
index 13380d8..b1fd688 100644 (file)
@@ -53,6 +53,9 @@
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utxfinit")
 
+/* For acpi_exec only */
+void ae_do_object_overrides(void);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_initialize_subsystem
@@ -65,6 +68,7 @@ ACPI_MODULE_NAME("utxfinit")
  *              called, so any early initialization belongs here.
  *
  ******************************************************************************/
+
 acpi_status __init acpi_initialize_subsystem(void)
 {
        acpi_status status;
@@ -275,6 +279,13 @@ acpi_status __init acpi_initialize_objects(u32 flags)
                        return_ACPI_STATUS(status);
                }
        }
+#ifdef ACPI_EXEC_APP
+       /*
+        * This call implements the "initialization file" option for acpi_exec.
+        * This is the precise point that we want to perform the overrides.
+        */
+       ae_do_object_overrides();
+#endif
 
        /*
         * Execute any module-level code that was detected during the table load
index 8ec8a89..d98ba43 100644 (file)
@@ -1180,6 +1180,10 @@ static int acpi_battery_add(struct acpi_device *device)
 
        if (!device)
                return -EINVAL;
+
+       if (device->dep_unmet)
+               return -EPROBE_DEFER;
+
        battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
        if (!battery)
                return -ENOMEM;
index 7db1931..076af81 100644 (file)
@@ -201,7 +201,7 @@ int acpi_device_set_power(struct acpi_device *device, int state)
         * Transition Power
         * ----------------
         * In accordance with the ACPI specification first apply power (via
-        * power resources) and then evalute _PSx.
+        * power resources) and then evaluate _PSx.
         */
        if (device->power.flags.power_resources) {
                result = acpi_power_transition(device, state);
index 447f6d6..163e82f 100644 (file)
@@ -173,4 +173,10 @@ static inline void suspend_nvs_restore(void) {}
 bool acpi_osi_is_win8(void);
 #endif
 
+/*--------------------------------------------------------------------------
+                               Device properties
+  -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
 #endif /* _ACPI_INTERNAL_H_ */
index 9964f70..f9eeae8 100644 (file)
@@ -436,7 +436,7 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
 static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
        if (!map->refcount) {
-               synchronize_rcu();
+               synchronize_rcu_expedited();
                acpi_unmap(map->phys, map->virt);
                kfree(map);
        }
@@ -1188,6 +1188,12 @@ EXPORT_SYMBOL(acpi_os_execute);
 
 void acpi_os_wait_events_complete(void)
 {
+       /*
+        * Make sure the GPE handler or the fixed event handler is not used
+        * on another CPU after removal.
+        */
+       if (acpi_irq_handler)
+               synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
        flush_workqueue(kacpid_wq);
        flush_workqueue(kacpi_notify_wq);
 }
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
new file mode 100644 (file)
index 0000000..a732e5d
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * intel_pmic.c - Intel PMIC operation region driver
+ *
+ * Copyright (C) 2014 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/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include "intel_pmic.h"
+
+#define PMIC_POWER_OPREGION_ID         0x8d
+#define PMIC_THERMAL_OPREGION_ID       0x8c
+
+struct acpi_lpat {
+       int temp;
+       int raw;
+};
+
+struct intel_pmic_opregion {
+       struct mutex lock;
+       struct acpi_lpat *lpat;
+       int lpat_count;
+       struct regmap *regmap;
+       struct intel_pmic_opregion_data *data;
+};
+
+static int pmic_get_reg_bit(int address, struct pmic_table *table,
+                           int count, int *reg, int *bit)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (table[i].address == address) {
+                       *reg = table[i].reg;
+                       if (bit)
+                               *bit = table[i].bit;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+/**
+ * raw_to_temp(): Return temperature from raw value through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @raw: the raw value, used as a key to get the temerature from the
+ *       above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
+{
+       int i, delta_temp, delta_raw, temp;
+
+       for (i = 0; i < count - 1; i++) {
+               if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
+                   (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
+                       break;
+       }
+
+       if (i == count - 1)
+               return -ENOENT;
+
+       delta_temp = lpat[i+1].temp - lpat[i].temp;
+       delta_raw = lpat[i+1].raw - lpat[i].raw;
+       temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
+
+       return temp;
+}
+
+/**
+ * temp_to_raw(): Return raw value from temperature through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @temp: the temperature, used as a key to get the raw value from the
+ *        above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
+{
+       int i, delta_temp, delta_raw, raw;
+
+       for (i = 0; i < count - 1; i++) {
+               if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
+                       break;
+       }
+
+       if (i == count - 1)
+               return -ENOENT;
+
+       delta_temp = lpat[i+1].temp - lpat[i].temp;
+       delta_raw = lpat[i+1].raw - lpat[i].raw;
+       raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
+
+       return raw;
+}
+
+static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
+                             acpi_handle handle, struct device *dev)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj_p, *obj_e;
+       int *lpat, i;
+       acpi_status status;
+
+       status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
+       if (ACPI_FAILURE(status))
+               return;
+
+       obj_p = (union acpi_object *)buffer.pointer;
+       if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
+           (obj_p->package.count % 2) || (obj_p->package.count < 4))
+               goto out;
+
+       lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
+                           GFP_KERNEL);
+       if (!lpat)
+               goto out;
+
+       for (i = 0; i < obj_p->package.count; i++) {
+               obj_e = &obj_p->package.elements[i];
+               if (obj_e->type != ACPI_TYPE_INTEGER) {
+                       devm_kfree(dev, lpat);
+                       goto out;
+               }
+               lpat[i] = (s64)obj_e->integer.value;
+       }
+
+       opregion->lpat = (struct acpi_lpat *)lpat;
+       opregion->lpat_count = obj_p->package.count / 2;
+
+out:
+       kfree(buffer.pointer);
+}
+
+static acpi_status intel_pmic_power_handler(u32 function,
+               acpi_physical_address address, u32 bits, u64 *value64,
+               void *handler_context, void *region_context)
+{
+       struct intel_pmic_opregion *opregion = region_context;
+       struct regmap *regmap = opregion->regmap;
+       struct intel_pmic_opregion_data *d = opregion->data;
+       int reg, bit, result;
+
+       if (bits != 32 || !value64)
+               return AE_BAD_PARAMETER;
+
+       if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
+               return AE_BAD_PARAMETER;
+
+       result = pmic_get_reg_bit(address, d->power_table,
+                                 d->power_table_count, &reg, &bit);
+       if (result == -ENOENT)
+               return AE_BAD_PARAMETER;
+
+       mutex_lock(&opregion->lock);
+
+       result = function == ACPI_READ ?
+               d->get_power(regmap, reg, bit, value64) :
+               d->update_power(regmap, reg, bit, *value64 == 1);
+
+       mutex_unlock(&opregion->lock);
+
+       return result ? AE_ERROR : AE_OK;
+}
+
+static int pmic_read_temp(struct intel_pmic_opregion *opregion,
+                         int reg, u64 *value)
+{
+       int raw_temp, temp;
+
+       if (!opregion->data->get_raw_temp)
+               return -ENXIO;
+
+       raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
+       if (raw_temp < 0)
+               return raw_temp;
+
+       if (!opregion->lpat) {
+               *value = raw_temp;
+               return 0;
+       }
+
+       temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);
+       if (temp < 0)
+               return temp;
+
+       *value = temp;
+       return 0;
+}
+
+static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
+                            u32 function, u64 *value)
+{
+       return function == ACPI_READ ?
+               pmic_read_temp(opregion, reg, value) : -EINVAL;
+}
+
+static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
+                           u32 function, u64 *value)
+{
+       int raw_temp;
+
+       if (function == ACPI_READ)
+               return pmic_read_temp(opregion, reg, value);
+
+       if (!opregion->data->update_aux)
+               return -ENXIO;
+
+       if (opregion->lpat) {
+               raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
+                                      *value);
+               if (raw_temp < 0)
+                       return raw_temp;
+       } else {
+               raw_temp = *value;
+       }
+
+       return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
+}
+
+static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
+                           u32 function, u64 *value)
+{
+       struct intel_pmic_opregion_data *d = opregion->data;
+       struct regmap *regmap = opregion->regmap;
+
+       if (!d->get_policy || !d->update_policy)
+               return -ENXIO;
+
+       if (function == ACPI_READ)
+               return d->get_policy(regmap, reg, value);
+
+       if (*value != 0 && *value != 1)
+               return -EINVAL;
+
+       return d->update_policy(regmap, reg, *value);
+}
+
+static bool pmic_thermal_is_temp(int address)
+{
+       return (address <= 0x3c) && !(address % 12);
+}
+
+static bool pmic_thermal_is_aux(int address)
+{
+       return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
+              (address >= 8 && address <= 0x44 && !((address - 8) % 12));
+}
+
+static bool pmic_thermal_is_pen(int address)
+{
+       return address >= 0x48 && address <= 0x5c;
+}
+
+static acpi_status intel_pmic_thermal_handler(u32 function,
+               acpi_physical_address address, u32 bits, u64 *value64,
+               void *handler_context, void *region_context)
+{
+       struct intel_pmic_opregion *opregion = region_context;
+       struct intel_pmic_opregion_data *d = opregion->data;
+       int reg, result;
+
+       if (bits != 32 || !value64)
+               return AE_BAD_PARAMETER;
+
+       result = pmic_get_reg_bit(address, d->thermal_table,
+                                 d->thermal_table_count, &reg, NULL);
+       if (result == -ENOENT)
+               return AE_BAD_PARAMETER;
+
+       mutex_lock(&opregion->lock);
+
+       if (pmic_thermal_is_temp(address))
+               result = pmic_thermal_temp(opregion, reg, function, value64);
+       else if (pmic_thermal_is_aux(address))
+               result = pmic_thermal_aux(opregion, reg, function, value64);
+       else if (pmic_thermal_is_pen(address))
+               result = pmic_thermal_pen(opregion, reg, function, value64);
+       else
+               result = -EINVAL;
+
+       mutex_unlock(&opregion->lock);
+
+       if (result < 0) {
+               if (result == -EINVAL)
+                       return AE_BAD_PARAMETER;
+               else
+                       return AE_ERROR;
+       }
+
+       return AE_OK;
+}
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
+                                       struct regmap *regmap,
+                                       struct intel_pmic_opregion_data *d)
+{
+       acpi_status status;
+       struct intel_pmic_opregion *opregion;
+
+       if (!dev || !regmap || !d)
+               return -EINVAL;
+
+       if (!handle)
+               return -ENODEV;
+
+       opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
+       if (!opregion)
+               return -ENOMEM;
+
+       mutex_init(&opregion->lock);
+       opregion->regmap = regmap;
+       pmic_thermal_lpat(opregion, handle, dev);
+
+       status = acpi_install_address_space_handler(handle,
+                                                   PMIC_POWER_OPREGION_ID,
+                                                   intel_pmic_power_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   PMIC_THERMAL_OPREGION_ID,
+                                                   intel_pmic_thermal_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status)) {
+               acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
+                                                 intel_pmic_power_handler);
+               return -ENODEV;
+       }
+
+       opregion->data = d;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h
new file mode 100644 (file)
index 0000000..d4e90af
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __INTEL_PMIC_H
+#define __INTEL_PMIC_H
+
+struct pmic_table {
+       int address;    /* operation region address */
+       int reg;        /* corresponding thermal register */
+       int bit;        /* control bit for power */
+};
+
+struct intel_pmic_opregion_data {
+       int (*get_power)(struct regmap *r, int reg, int bit, u64 *value);
+       int (*update_power)(struct regmap *r, int reg, int bit, bool on);
+       int (*get_raw_temp)(struct regmap *r, int reg);
+       int (*update_aux)(struct regmap *r, int reg, int raw_temp);
+       int (*get_policy)(struct regmap *r, int reg, u64 *value);
+       int (*update_policy)(struct regmap *r, int reg, int enable);
+       struct pmic_table *power_table;
+       int power_table_count;
+       struct pmic_table *thermal_table;
+       int thermal_table_count;
+};
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d);
+
+#endif
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c
new file mode 100644 (file)
index 0000000..ef7d8ff
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver
+ *
+ * Copyright (C) 2014 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/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include "intel_pmic.h"
+
+#define PWR_SOURCE_SELECT      BIT(1)
+
+#define PMIC_A0LOCK_REG                0xc5
+
+static struct pmic_table power_table[] = {
+       {
+               .address = 0x24,
+               .reg = 0x66,
+               .bit = 0x00,
+       },
+       {
+               .address = 0x48,
+               .reg = 0x5d,
+               .bit = 0x00,
+       },
+};
+
+static struct pmic_table thermal_table[] = {
+       {
+               .address = 0x00,
+               .reg = 0x75
+       },
+       {
+               .address = 0x04,
+               .reg = 0x95
+       },
+       {
+               .address = 0x08,
+               .reg = 0x97
+       },
+       {
+               .address = 0x0c,
+               .reg = 0x77
+       },
+       {
+               .address = 0x10,
+               .reg = 0x9a
+       },
+       {
+               .address = 0x14,
+               .reg = 0x9c
+       },
+       {
+               .address = 0x18,
+               .reg = 0x79
+       },
+       {
+               .address = 0x1c,
+               .reg = 0x9f
+       },
+       {
+               .address = 0x20,
+               .reg = 0xa1
+       },
+       {
+               .address = 0x48,
+               .reg = 0x94
+       },
+       {
+               .address = 0x4c,
+               .reg = 0x99
+       },
+       {
+               .address = 0x50,
+               .reg = 0x9e
+       },
+};
+
+static int intel_crc_pmic_get_power(struct regmap *regmap, int reg,
+                                   int bit, u64 *value)
+{
+       int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0;
+       return 0;
+}
+
+static int intel_crc_pmic_update_power(struct regmap *regmap, int reg,
+                                      int bit, bool on)
+{
+       int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       if (on) {
+               data |= PWR_SOURCE_SELECT | BIT(bit);
+       } else {
+               data &= ~BIT(bit);
+               data |= PWR_SOURCE_SELECT;
+       }
+
+       if (regmap_write(regmap, reg, data))
+               return -EIO;
+       return 0;
+}
+
+static int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+       int temp_l, temp_h;
+
+       /*
+        * Raw temperature value is 10bits: 8bits in reg
+        * and 2bits in reg-1: bit0,1
+        */
+       if (regmap_read(regmap, reg, &temp_l) ||
+           regmap_read(regmap, reg - 1, &temp_h))
+               return -EIO;
+
+       return temp_l | (temp_h & 0x3) << 8;
+}
+
+static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw)
+{
+       return regmap_write(regmap, reg, raw) ||
+               regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0;
+}
+
+static int intel_crc_pmic_get_policy(struct regmap *regmap, int reg, u64 *value)
+{
+       int pen;
+
+       if (regmap_read(regmap, reg, &pen))
+               return -EIO;
+       *value = pen >> 7;
+       return 0;
+}
+
+static int intel_crc_pmic_update_policy(struct regmap *regmap,
+                                       int reg, int enable)
+{
+       int alert0;
+
+       /* Update to policy enable bit requires unlocking a0lock */
+       if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0))
+               return -EIO;
+
+       if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0))
+               return -EIO;
+
+       if (regmap_update_bits(regmap, reg, 0x80, enable << 7))
+               return -EIO;
+
+       /* restore alert0 */
+       if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0))
+               return -EIO;
+
+       return 0;
+}
+
+static struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = {
+       .get_power      = intel_crc_pmic_get_power,
+       .update_power   = intel_crc_pmic_update_power,
+       .get_raw_temp   = intel_crc_pmic_get_raw_temp,
+       .update_aux     = intel_crc_pmic_update_aux,
+       .get_policy     = intel_crc_pmic_get_policy,
+       .update_policy  = intel_crc_pmic_update_policy,
+       .power_table    = power_table,
+       .power_table_count= ARRAY_SIZE(power_table),
+       .thermal_table  = thermal_table,
+       .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
+{
+       struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+       return intel_pmic_install_opregion_handler(&pdev->dev,
+                       ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
+                       &intel_crc_pmic_opregion_data);
+}
+
+static struct platform_driver intel_crc_pmic_opregion_driver = {
+       .probe = intel_crc_pmic_opregion_probe,
+       .driver = {
+               .name = "crystal_cove_pmic",
+       },
+};
+
+static int __init intel_crc_pmic_opregion_driver_init(void)
+{
+       return platform_driver_register(&intel_crc_pmic_opregion_driver);
+}
+module_init(intel_crc_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("CrystalCove ACPI opration region driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
new file mode 100644 (file)
index 0000000..6a082d4
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
+ *
+ * Copyright (C) 2014 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/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/iio/consumer.h>
+#include "intel_pmic.h"
+
+#define XPOWER_GPADC_LOW       0x5b
+
+static struct pmic_table power_table[] = {
+       {
+               .address = 0x00,
+               .reg = 0x13,
+               .bit = 0x05,
+       },
+       {
+               .address = 0x04,
+               .reg = 0x13,
+               .bit = 0x06,
+       },
+       {
+               .address = 0x08,
+               .reg = 0x13,
+               .bit = 0x07,
+       },
+       {
+               .address = 0x0c,
+               .reg = 0x12,
+               .bit = 0x03,
+       },
+       {
+               .address = 0x10,
+               .reg = 0x12,
+               .bit = 0x04,
+       },
+       {
+               .address = 0x14,
+               .reg = 0x12,
+               .bit = 0x05,
+       },
+       {
+               .address = 0x18,
+               .reg = 0x12,
+               .bit = 0x06,
+       },
+       {
+               .address = 0x1c,
+               .reg = 0x12,
+               .bit = 0x00,
+       },
+       {
+               .address = 0x20,
+               .reg = 0x12,
+               .bit = 0x01,
+       },
+       {
+               .address = 0x24,
+               .reg = 0x12,
+               .bit = 0x02,
+       },
+       {
+               .address = 0x28,
+               .reg = 0x13,
+               .bit = 0x02,
+       },
+       {
+               .address = 0x2c,
+               .reg = 0x13,
+               .bit = 0x03,
+       },
+       {
+               .address = 0x30,
+               .reg = 0x13,
+               .bit = 0x04,
+       },
+       {
+               .address = 0x38,
+               .reg = 0x10,
+               .bit = 0x03,
+       },
+       {
+               .address = 0x3c,
+               .reg = 0x10,
+               .bit = 0x06,
+       },
+       {
+               .address = 0x40,
+               .reg = 0x10,
+               .bit = 0x05,
+       },
+       {
+               .address = 0x44,
+               .reg = 0x10,
+               .bit = 0x04,
+       },
+       {
+               .address = 0x48,
+               .reg = 0x10,
+               .bit = 0x01,
+       },
+       {
+               .address = 0x4c,
+               .reg = 0x10,
+               .bit = 0x00
+       },
+};
+
+/* TMP0 - TMP5 are the same, all from GPADC */
+static struct pmic_table thermal_table[] = {
+       {
+               .address = 0x00,
+               .reg = XPOWER_GPADC_LOW
+       },
+       {
+               .address = 0x0c,
+               .reg = XPOWER_GPADC_LOW
+       },
+       {
+               .address = 0x18,
+               .reg = XPOWER_GPADC_LOW
+       },
+       {
+               .address = 0x24,
+               .reg = XPOWER_GPADC_LOW
+       },
+       {
+               .address = 0x30,
+               .reg = XPOWER_GPADC_LOW
+       },
+       {
+               .address = 0x3c,
+               .reg = XPOWER_GPADC_LOW
+       },
+};
+
+static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
+                                      int bit, u64 *value)
+{
+       int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = (data & BIT(bit)) ? 1 : 0;
+       return 0;
+}
+
+static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
+                                         int bit, bool on)
+{
+       int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       if (on)
+               data |= BIT(bit);
+       else
+               data &= ~BIT(bit);
+
+       if (regmap_write(regmap, reg, data))
+               return -EIO;
+
+       return 0;
+}
+
+/**
+ * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
+ *
+ * @regmap: regmap of the PMIC device
+ * @reg: register to get the reading
+ *
+ * We could get the sensor value by manipulating the HW regs here, but since
+ * the axp288 IIO driver may also access the same regs at the same time, the
+ * APIs provided by IIO subsystem are used here instead to avoid problems. As
+ * a result, the two passed in params are of no actual use.
+ *
+ * Return a positive value on success, errno on failure.
+ */
+static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+       struct iio_channel *gpadc_chan;
+       int ret, val;
+
+       gpadc_chan = iio_channel_get(NULL, "axp288-system-temp");
+       if (IS_ERR_OR_NULL(gpadc_chan))
+               return -EACCES;
+
+       ret = iio_read_channel_raw(gpadc_chan, &val);
+       if (ret < 0)
+               val = ret;
+
+       iio_channel_release(gpadc_chan);
+       return val;
+}
+
+static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
+       .get_power = intel_xpower_pmic_get_power,
+       .update_power = intel_xpower_pmic_update_power,
+       .get_raw_temp = intel_xpower_pmic_get_raw_temp,
+       .power_table = power_table,
+       .power_table_count = ARRAY_SIZE(power_table),
+       .thermal_table = thermal_table,
+       .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
+               acpi_physical_address address, u32 bit_width, u64 *value,
+               void *handler_context, void *region_context)
+{
+       return AE_OK;
+}
+
+static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
+{
+       struct device *parent = pdev->dev.parent;
+       struct axp20x_dev *axp20x = dev_get_drvdata(parent);
+       acpi_status status;
+       int result;
+
+       status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
+                       ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
+                       NULL, NULL);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       result = intel_pmic_install_opregion_handler(&pdev->dev,
+                                       ACPI_HANDLE(parent), axp20x->regmap,
+                                       &intel_xpower_pmic_opregion_data);
+       if (result)
+               acpi_remove_address_space_handler(ACPI_HANDLE(parent),
+                                                 ACPI_ADR_SPACE_GPIO,
+                                                 intel_xpower_pmic_gpio_handler);
+
+       return result;
+}
+
+static struct platform_driver intel_xpower_pmic_opregion_driver = {
+       .probe = intel_xpower_pmic_opregion_probe,
+       .driver = {
+               .name = "axp288_pmic_acpi",
+       },
+};
+
+static int __init intel_xpower_pmic_opregion_driver_init(void)
+{
+       return platform_driver_register(&intel_xpower_pmic_opregion_driver);
+}
+module_init(intel_xpower_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("XPower AXP288 ACPI operation region driver");
+MODULE_LICENSE("GPL");
index 17f9ec5..38472fd 100644 (file)
@@ -334,10 +334,10 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
 
 static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 {
-       acpi_status status = 0;
+       acpi_status status;
        u64 count;
        int current_count;
-       int i;
+       int i, ret = 0;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *cst;
 
@@ -358,7 +358,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
        /* There must be at least 2 elements */
        if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
                printk(KERN_ERR PREFIX "not enough elements in _CST\n");
-               status = -EFAULT;
+               ret = -EFAULT;
                goto end;
        }
 
@@ -367,7 +367,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
        /* Validate number of power states. */
        if (count < 1 || count != cst->package.count - 1) {
                printk(KERN_ERR PREFIX "count given by _CST is not valid\n");
-               status = -EFAULT;
+               ret = -EFAULT;
                goto end;
        }
 
@@ -489,12 +489,12 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
 
        /* Validate number of power states discovered */
        if (current_count < 2)
-               status = -EFAULT;
+               ret = -EFAULT;
 
       end:
        kfree(buffer.pointer);
 
-       return status;
+       return ret;
 }
 
 static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
@@ -1111,7 +1111,7 @@ static int acpi_processor_registered;
 
 int acpi_processor_power_init(struct acpi_processor *pr)
 {
-       acpi_status status = 0;
+       acpi_status status;
        int retval;
        struct cpuidle_device *dev;
        static int first_run;
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
new file mode 100644 (file)
index 0000000..0d08373
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *          Darren Hart <dvhart@linux.intel.com>
+ *          Rafael J. Wysocki <rafael.j.wysocki@intel.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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+       0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+       0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+       int j;
+
+       /*
+        * The value must be an integer, a string, a reference, or a package
+        * whose every element must be an integer, a string, or a reference.
+        */
+       switch (value->type) {
+       case ACPI_TYPE_INTEGER:
+       case ACPI_TYPE_STRING:
+       case ACPI_TYPE_LOCAL_REFERENCE:
+               return true;
+
+       case ACPI_TYPE_PACKAGE:
+               for (j = 0; j < value->package.count; j++)
+                       switch (value->package.elements[j].type) {
+                       case ACPI_TYPE_INTEGER:
+                       case ACPI_TYPE_STRING:
+                       case ACPI_TYPE_LOCAL_REFERENCE:
+                               continue;
+
+                       default:
+                               return false;
+                       }
+
+               return true;
+       }
+       return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+       int i;
+
+       for (i = 0; i < properties->package.count; i++) {
+               const union acpi_object *property;
+
+               property = &properties->package.elements[i];
+               /*
+                * Only two elements allowed, the first one must be a string and
+                * the second one has to satisfy certain conditions.
+                */
+               if (property->package.count != 2
+                   || property->package.elements[0].type != ACPI_TYPE_STRING
+                   || !acpi_property_value_ok(&property->package.elements[1]))
+                       return false;
+       }
+       return true;
+}
+
+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+       const union acpi_object *of_compatible;
+       struct acpi_hardware_id *hwid;
+       bool acpi_of = false;
+       int ret;
+
+       /*
+        * Check if the special PRP0001 ACPI ID is present and in that
+        * case we fill in Device Tree compatible properties for this
+        * device.
+        */
+       list_for_each_entry(hwid, &adev->pnp.ids, list) {
+               if (!strcmp(hwid->id, "PRP0001")) {
+                       acpi_of = true;
+                       break;
+               }
+       }
+
+       if (!acpi_of)
+               return;
+
+       ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+                                         &of_compatible);
+       if (ret) {
+               ret = acpi_dev_get_property(adev, "compatible",
+                                           ACPI_TYPE_STRING, &of_compatible);
+               if (ret) {
+                       acpi_handle_warn(adev->handle,
+                                        "PRP0001 requires compatible property\n");
+                       return;
+               }
+       }
+       adev->data.of_compatible = of_compatible;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+       const union acpi_object *desc;
+       acpi_status status;
+       int i;
+
+       status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+                                           ACPI_TYPE_PACKAGE);
+       if (ACPI_FAILURE(status))
+               return;
+
+       desc = buf.pointer;
+       if (desc->package.count % 2)
+               goto fail;
+
+       /* Look for the device properties UUID. */
+       for (i = 0; i < desc->package.count; i += 2) {
+               const union acpi_object *uuid, *properties;
+
+               uuid = &desc->package.elements[i];
+               properties = &desc->package.elements[i + 1];
+
+               /*
+                * The first element must be a UUID and the second one must be
+                * a package.
+                */
+               if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+                   || properties->type != ACPI_TYPE_PACKAGE)
+                       break;
+
+               if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+                       continue;
+
+               /*
+                * We found the matching UUID. Now validate the format of the
+                * package immediately following it.
+                */
+               if (!acpi_properties_format_valid(properties))
+                       break;
+
+               adev->data.pointer = buf.pointer;
+               adev->data.properties = properties;
+
+               acpi_init_of_compatible(adev);
+               return;
+       }
+
+ fail:
+       dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+       ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+       ACPI_FREE((void *)adev->data.pointer);
+       adev->data.of_compatible = NULL;
+       adev->data.pointer = NULL;
+       adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected property type
+ * @obj: Location to store the property value (if not %NULL)
+ *
+ * Look up a property with @name and store a pointer to the resulting ACPI
+ * object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects.  These objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if property with @name has been found (success),
+ *         %-EINVAL if the arguments are invalid,
+ *         %-ENODATA if the property doesn't exist,
+ *         %-EPROTO if the property value type doesn't match @type.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+                         acpi_object_type type, const union acpi_object **obj)
+{
+       const union acpi_object *properties;
+       int i;
+
+       if (!adev || !name)
+               return -EINVAL;
+
+       if (!adev->data.pointer || !adev->data.properties)
+               return -ENODATA;
+
+       properties = adev->data.properties;
+       for (i = 0; i < properties->package.count; i++) {
+               const union acpi_object *propname, *propvalue;
+               const union acpi_object *property;
+
+               property = &properties->package.elements[i];
+
+               propname = &property->package.elements[0];
+               propvalue = &property->package.elements[1];
+
+               if (!strcmp(name, propname->string.pointer)) {
+                       if (type != ACPI_TYPE_ANY && propvalue->type != type)
+                               return -EPROTO;
+                       else if (obj)
+                               *obj = propvalue;
+
+                       return 0;
+               }
+       }
+       return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected type of array elements
+ * @obj: Location to store a pointer to the property value (if not NULL)
+ *
+ * Look up an array property with @name and store a pointer to the resulting
+ * ACPI object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects.  Those objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if array property (package) with @name has been found (success),
+ *         %-EINVAL if the arguments are invalid,
+ *         %-ENODATA if the property doesn't exist,
+ *         %-EPROTO if the property is not a package or the type of its elements
+ *           doesn't match @type.
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+                               acpi_object_type type,
+                               const union acpi_object **obj)
+{
+       const union acpi_object *prop;
+       int ret, i;
+
+       ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+       if (ret)
+               return ret;
+
+       if (type != ACPI_TYPE_ANY) {
+               /* Check that all elements are of correct type. */
+               for (i = 0; i < prop->package.count; i++)
+                       if (prop->package.elements[i].type != type)
+                               return -EPROTO;
+       }
+       if (obj)
+               *obj = prop;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @index: Index of the reference to return
+ * @args: Location to store the returned reference with optional arguments
+ *
+ * Find property with @name, verifify that it is a package containing at least
+ * one object reference and if so, store the ACPI device object pointer to the
+ * target object in @args->adev.  If the reference includes arguments, store
+ * them in the @args->args[] array.
+ *
+ * If there's more than one reference in the property value package, @index is
+ * used to select the one to return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+                                   const char *name, size_t index,
+                                   struct acpi_reference_args *args)
+{
+       const union acpi_object *element, *end;
+       const union acpi_object *obj;
+       struct acpi_device *device;
+       int ret, idx = 0;
+
+       ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+       if (ret)
+               return ret;
+
+       /*
+        * The simplest case is when the value is a single reference.  Just
+        * return that reference then.
+        */
+       if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+               if (index)
+                       return -EINVAL;
+
+               ret = acpi_bus_get_device(obj->reference.handle, &device);
+               if (ret)
+                       return ret;
+
+               args->adev = device;
+               args->nargs = 0;
+               return 0;
+       }
+
+       /*
+        * If it is not a single reference, then it is a package of
+        * references followed by number of ints as follows:
+        *
+        *  Package () { REF, INT, REF, INT, INT }
+        *
+        * The index argument is then used to determine which reference
+        * the caller wants (along with the arguments).
+        */
+       if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+               return -EPROTO;
+
+       element = obj->package.elements;
+       end = element + obj->package.count;
+
+       while (element < end) {
+               u32 nargs, i;
+
+               if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+                       return -EPROTO;
+
+               ret = acpi_bus_get_device(element->reference.handle, &device);
+               if (ret)
+                       return -ENODEV;
+
+               element++;
+               nargs = 0;
+
+               /* assume following integer elements are all args */
+               for (i = 0; element + i < end; i++) {
+                       int type = element[i].type;
+
+                       if (type == ACPI_TYPE_INTEGER)
+                               nargs++;
+                       else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+                               break;
+                       else
+                               return -EPROTO;
+               }
+
+               if (idx++ == index) {
+                       args->adev = device;
+                       args->nargs = nargs;
+                       for (i = 0; i < nargs; i++)
+                               args->args[i] = element[i].integer.value;
+
+                       return 0;
+               }
+
+               element += nargs;
+       }
+
+       return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+                     void **valptr)
+{
+       return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+                                    (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+                             enum dev_prop_type proptype, void *val)
+{
+       const union acpi_object *obj;
+       int ret;
+
+       if (!val)
+               return -EINVAL;
+
+       if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+               ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+               if (ret)
+                       return ret;
+
+               switch (proptype) {
+               case DEV_PROP_U8:
+                       if (obj->integer.value > U8_MAX)
+                               return -EOVERFLOW;
+                       *(u8 *)val = obj->integer.value;
+                       break;
+               case DEV_PROP_U16:
+                       if (obj->integer.value > U16_MAX)
+                               return -EOVERFLOW;
+                       *(u16 *)val = obj->integer.value;
+                       break;
+               case DEV_PROP_U32:
+                       if (obj->integer.value > U32_MAX)
+                               return -EOVERFLOW;
+                       *(u32 *)val = obj->integer.value;
+                       break;
+               default:
+                       *(u64 *)val = obj->integer.value;
+                       break;
+               }
+       } else if (proptype == DEV_PROP_STRING) {
+               ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+               if (ret)
+                       return ret;
+
+               *(char **)val = obj->string.pointer;
+       } else {
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+                                      size_t nval)
+{
+       int i;
+
+       for (i = 0; i < nval; i++) {
+               if (items[i].type != ACPI_TYPE_INTEGER)
+                       return -EPROTO;
+               if (items[i].integer.value > U8_MAX)
+                       return -EOVERFLOW;
+
+               val[i] = items[i].integer.value;
+       }
+       return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+                                       u16 *val, size_t nval)
+{
+       int i;
+
+       for (i = 0; i < nval; i++) {
+               if (items[i].type != ACPI_TYPE_INTEGER)
+                       return -EPROTO;
+               if (items[i].integer.value > U16_MAX)
+                       return -EOVERFLOW;
+
+               val[i] = items[i].integer.value;
+       }
+       return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+                                       u32 *val, size_t nval)
+{
+       int i;
+
+       for (i = 0; i < nval; i++) {
+               if (items[i].type != ACPI_TYPE_INTEGER)
+                       return -EPROTO;
+               if (items[i].integer.value > U32_MAX)
+                       return -EOVERFLOW;
+
+               val[i] = items[i].integer.value;
+       }
+       return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+                                       u64 *val, size_t nval)
+{
+       int i;
+
+       for (i = 0; i < nval; i++) {
+               if (items[i].type != ACPI_TYPE_INTEGER)
+                       return -EPROTO;
+
+               val[i] = items[i].integer.value;
+       }
+       return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+                                          char **val, size_t nval)
+{
+       int i;
+
+       for (i = 0; i < nval; i++) {
+               if (items[i].type != ACPI_TYPE_STRING)
+                       return -EPROTO;
+
+               val[i] = items[i].string.pointer;
+       }
+       return 0;
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+                      enum dev_prop_type proptype, void *val, size_t nval)
+{
+       const union acpi_object *obj;
+       const union acpi_object *items;
+       int ret;
+
+       if (val && nval == 1) {
+               ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
+               if (!ret)
+                       return ret;
+       }
+
+       ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+       if (ret)
+               return ret;
+
+       if (!val)
+               return obj->package.count;
+       else if (nval <= 0)
+               return -EINVAL;
+
+       if (nval > obj->package.count)
+               return -EOVERFLOW;
+
+       items = obj->package.elements;
+       switch (proptype) {
+       case DEV_PROP_U8:
+               ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+               break;
+       case DEV_PROP_U16:
+               ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+               break;
+       case DEV_PROP_U32:
+               ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+               break;
+       case DEV_PROP_U64:
+               ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+               break;
+       case DEV_PROP_STRING:
+               ret = acpi_copy_property_array_string(items, (char **)val, nval);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
index 0476e90..1b1cf55 100644 (file)
@@ -36,6 +36,8 @@ bool acpi_force_hot_remove;
 
 static const char *dummy_hid = "device";
 
+static LIST_HEAD(acpi_dep_list);
+static DEFINE_MUTEX(acpi_dep_list_lock);
 static LIST_HEAD(acpi_bus_id_list);
 static DEFINE_MUTEX(acpi_scan_lock);
 static LIST_HEAD(acpi_scan_handlers_list);
@@ -43,6 +45,12 @@ DEFINE_MUTEX(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
 static DEFINE_MUTEX(acpi_hp_context_lock);
 
+struct acpi_dep_data {
+       struct list_head node;
+       acpi_handle master;
+       acpi_handle slave;
+};
+
 struct acpi_device_bus_id{
        char bus_id[15];
        unsigned int instance_no;
@@ -124,17 +132,56 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
        if (list_empty(&acpi_dev->pnp.ids))
                return 0;
 
-       len = snprintf(modalias, size, "acpi:");
-       size -= len;
-
-       list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
-               count = snprintf(&modalias[len], size, "%s:", id->id);
-               if (count < 0)
-                       return -EINVAL;
-               if (count >= size)
-                       return -ENOMEM;
-               len += count;
-               size -= count;
+       /*
+        * If the device has PRP0001 we expose DT compatible modalias
+        * instead in form of of:NnameTCcompatible.
+        */
+       if (acpi_dev->data.of_compatible) {
+               struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+               const union acpi_object *of_compatible, *obj;
+               int i, nval;
+               char *c;
+
+               acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+               /* DT strings are all in lower case */
+               for (c = buf.pointer; *c != '\0'; c++)
+                       *c = tolower(*c);
+
+               len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+               ACPI_FREE(buf.pointer);
+
+               of_compatible = acpi_dev->data.of_compatible;
+               if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+                       nval = of_compatible->package.count;
+                       obj = of_compatible->package.elements;
+               } else { /* Must be ACPI_TYPE_STRING. */
+                       nval = 1;
+                       obj = of_compatible;
+               }
+               for (i = 0; i < nval; i++, obj++) {
+                       count = snprintf(&modalias[len], size, "C%s",
+                                        obj->string.pointer);
+                       if (count < 0)
+                               return -EINVAL;
+                       if (count >= size)
+                               return -ENOMEM;
+
+                       len += count;
+                       size -= count;
+               }
+       } else {
+               len = snprintf(modalias, size, "acpi:");
+               size -= len;
+
+               list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+                       count = snprintf(&modalias[len], size, "%s:", id->id);
+                       if (count < 0)
+                               return -EINVAL;
+                       if (count >= size)
+                               return -ENOMEM;
+                       len += count;
+                       size -= count;
+               }
        }
 
        modalias[len] = '\0';
@@ -902,6 +949,51 @@ int acpi_match_device_ids(struct acpi_device *device,
 }
 EXPORT_SYMBOL(acpi_match_device_ids);
 
+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+                                       const struct device_driver *drv)
+{
+       const union acpi_object *of_compatible, *obj;
+       struct acpi_device *adev;
+       int i, nval;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               return false;
+
+       of_compatible = adev->data.of_compatible;
+       if (!drv->of_match_table || !of_compatible)
+               return false;
+
+       if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+               nval = of_compatible->package.count;
+               obj = of_compatible->package.elements;
+       } else { /* Must be ACPI_TYPE_STRING. */
+               nval = 1;
+               obj = of_compatible;
+       }
+       /* Now we can look for the driver DT compatible strings */
+       for (i = 0; i < nval; i++, obj++) {
+               const struct of_device_id *id;
+
+               for (id = drv->of_match_table; id->compatible[0]; id++)
+                       if (!strcasecmp(obj->string.pointer, id->compatible))
+                               return true;
+       }
+
+       return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+                             const struct device_driver *drv)
+{
+       if (!drv->acpi_match_table)
+               return acpi_of_driver_match_device(dev, drv);
+
+       return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
 static void acpi_free_power_resources_lists(struct acpi_device *device)
 {
        int i;
@@ -922,6 +1014,7 @@ static void acpi_device_release(struct device *dev)
 {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
 
+       acpi_free_properties(acpi_dev);
        acpi_free_pnp_ids(&acpi_dev->pnp);
        acpi_free_power_resources_lists(acpi_dev);
        kfree(acpi_dev);
@@ -1304,6 +1397,26 @@ int acpi_device_add(struct acpi_device *device,
        return result;
 }
 
+struct acpi_device *acpi_get_next_child(struct device *dev,
+                                       struct acpi_device *child)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct list_head *head, *next;
+
+       if (!adev)
+               return NULL;
+
+       head = &adev->children;
+       if (list_empty(head))
+               return NULL;
+
+       if (!child)
+               return list_first_entry(head, struct acpi_device, node);
+
+       next = child->node.next;
+       return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
 /* --------------------------------------------------------------------------
                                  Driver Management
    -------------------------------------------------------------------------- */
@@ -1923,9 +2036,11 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
        device->device_type = type;
        device->handle = handle;
        device->parent = acpi_bus_get_parent(handle);
+       device->fwnode.type = FWNODE_ACPI;
        acpi_set_device_status(device, sta);
        acpi_device_get_busid(device);
        acpi_set_pnp_ids(handle, &device->pnp, type);
+       acpi_init_properties(device);
        acpi_bus_get_flags(device);
        device->flags.match_driver = false;
        device->flags.initialized = true;
@@ -2086,6 +2201,59 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
        }
 }
 
+static void acpi_device_dep_initialize(struct acpi_device *adev)
+{
+       struct acpi_dep_data *dep;
+       struct acpi_handle_list dep_devices;
+       acpi_status status;
+       int i;
+
+       if (!acpi_has_method(adev->handle, "_DEP"))
+               return;
+
+       status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+                                       &dep_devices);
+       if (ACPI_FAILURE(status)) {
+               dev_err(&adev->dev, "Failed to evaluate _DEP.\n");
+               return;
+       }
+
+       for (i = 0; i < dep_devices.count; i++) {
+               struct acpi_device_info *info;
+               int skip;
+
+               status = acpi_get_object_info(dep_devices.handles[i], &info);
+               if (ACPI_FAILURE(status)) {
+                       dev_err(&adev->dev, "Error reading device info\n");
+                       continue;
+               }
+
+               /*
+                * Skip the dependency of Windows System Power
+                * Management Controller
+                */
+               skip = info->valid & ACPI_VALID_HID &&
+                       !strcmp(info->hardware_id.string, "INT3396");
+
+               kfree(info);
+
+               if (skip)
+                       continue;
+
+               dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL);
+               if (!dep)
+                       return;
+
+               dep->master = dep_devices.handles[i];
+               dep->slave  = adev->handle;
+               adev->dep_unmet++;
+
+               mutex_lock(&acpi_dep_list_lock);
+               list_add_tail(&dep->node , &acpi_dep_list);
+               mutex_unlock(&acpi_dep_list_lock);
+       }
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
                                      void *not_used, void **return_value)
 {
@@ -2112,6 +2280,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
                return AE_CTRL_DEPTH;
 
        acpi_scan_init_hotplug(device);
+       acpi_device_dep_initialize(device);
 
  out:
        if (!*return_value)
@@ -2232,6 +2401,29 @@ static void acpi_bus_attach(struct acpi_device *device)
                device->handler->hotplug.notify_online(device);
 }
 
+void acpi_walk_dep_device_list(acpi_handle handle)
+{
+       struct acpi_dep_data *dep, *tmp;
+       struct acpi_device *adev;
+
+       mutex_lock(&acpi_dep_list_lock);
+       list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
+               if (dep->master == handle) {
+                       acpi_bus_get_device(dep->slave, &adev);
+                       if (!adev)
+                               continue;
+
+                       adev->dep_unmet--;
+                       if (!adev->dep_unmet)
+                               acpi_bus_attach(adev);
+                       list_del(&dep->node);
+                       kfree(dep);
+               }
+       }
+       mutex_unlock(&acpi_dep_list_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
+
 /**
  * acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
  * @handle: Root of the namespace scope to scan.
index 05a31b5..8aa9254 100644 (file)
@@ -630,6 +630,7 @@ static int acpi_freeze_begin(void)
 static int acpi_freeze_prepare(void)
 {
        acpi_enable_all_wakeup_gpes();
+       acpi_os_wait_events_complete();
        enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
        return 0;
 }
@@ -825,6 +826,7 @@ static void acpi_power_off_prepare(void)
        /* Prepare to power off the system */
        acpi_sleep_prepare(ACPI_STATE_S5);
        acpi_disable_all_gpes();
+       acpi_os_wait_events_complete();
 }
 
 static void acpi_power_off(void)
index 6d5a6cd..93b8152 100644 (file)
@@ -190,30 +190,24 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
        }
 }
 
-
 int __init
-acpi_table_parse_entries(char *id,
-                            unsigned long table_size,
-                            int entry_id,
-                            acpi_tbl_entry_handler handler,
-                            unsigned int max_entries)
+acpi_parse_entries(char *id, unsigned long table_size,
+               acpi_tbl_entry_handler handler,
+               struct acpi_table_header *table_header,
+               int entry_id, unsigned int max_entries)
 {
-       struct acpi_table_header *table_header = NULL;
        struct acpi_subtable_header *entry;
-       unsigned int count = 0;
+       int count = 0;
        unsigned long table_end;
-       acpi_size tbl_size;
 
        if (acpi_disabled)
                return -ENODEV;
 
-       if (!handler)
+       if (!id || !handler)
                return -EINVAL;
 
-       if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
-               acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
-       else
-               acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
+       if (!table_size)
+               return -EINVAL;
 
        if (!table_header) {
                pr_warn("%4.4s not present\n", id);
@@ -230,9 +224,12 @@ acpi_table_parse_entries(char *id,
        while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
               table_end) {
                if (entry->type == entry_id
-                   && (!max_entries || count++ < max_entries))
+                   && (!max_entries || count < max_entries)) {
                        if (handler(entry, table_end))
-                               goto err;
+                               return -EINVAL;
+
+                       count++;
+               }
 
                /*
                 * If entry->length is 0, break from this loop to avoid
@@ -240,22 +237,53 @@ acpi_table_parse_entries(char *id,
                 */
                if (entry->length == 0) {
                        pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
-                       goto err;
+                       return -EINVAL;
                }
 
                entry = (struct acpi_subtable_header *)
                    ((unsigned long)entry + entry->length);
        }
+
        if (max_entries && count > max_entries) {
                pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
                        id, entry_id, count - max_entries, count);
        }
 
-       early_acpi_os_unmap_memory((char *)table_header, tbl_size);
        return count;
-err:
+}
+
+int __init
+acpi_table_parse_entries(char *id,
+                        unsigned long table_size,
+                        int entry_id,
+                        acpi_tbl_entry_handler handler,
+                        unsigned int max_entries)
+{
+       struct acpi_table_header *table_header = NULL;
+       acpi_size tbl_size;
+       int count;
+       u32 instance = 0;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (!id || !handler)
+               return -EINVAL;
+
+       if (!strncmp(id, ACPI_SIG_MADT, 4))
+               instance = acpi_apic_instance;
+
+       acpi_get_table_with_size(id, instance, &table_header, &tbl_size);
+       if (!table_header) {
+               pr_warn("%4.4s not present\n", id);
+               return -ENODEV;
+       }
+
+       count = acpi_parse_entries(id, table_size, handler, table_header,
+                       entry_id, max_entries);
+
        early_acpi_os_unmap_memory((char *)table_header, tbl_size);
-       return -EINVAL;
+       return count;
 }
 
 int __init
index 371ac12..dd8ff63 100644 (file)
@@ -136,8 +136,7 @@ acpi_extract_package(union acpi_object *package,
                                break;
                        case 'B':
                                size_required +=
-                                   sizeof(u8 *) +
-                                   (element->buffer.length * sizeof(u8));
+                                   sizeof(u8 *) + element->buffer.length;
                                tail_offset += sizeof(u8 *);
                                break;
                        default:
@@ -255,7 +254,7 @@ acpi_extract_package(union acpi_object *package,
                                memcpy(tail, element->buffer.pointer,
                                       element->buffer.length);
                                head += sizeof(u8 *);
-                               tail += element->buffer.length * sizeof(u8);
+                               tail += element->buffer.length;
                                break;
                        default:
                                /* Should never get here */
index e45f837..49f1e68 100644 (file)
@@ -321,6 +321,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
        { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
        { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
+       { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
        { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
@@ -492,6 +495,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
         * enabled.  https://bugzilla.kernel.org/show_bug.cgi?id=60731
         */
        { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
+       { PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
 
        /* Enmotus */
        { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
index 07bc7e4..6507159 100644 (file)
@@ -1488,7 +1488,7 @@ static int sata_fsl_probe(struct platform_device *ofdev)
        host_priv->csr_base = csr_base;
 
        irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
-       if (irq < 0) {
+       if (!irq) {
                dev_err(&ofdev->dev, "invalid irq from platform\n");
                goto error_exit_with_cleanup;
        }
index 6922cd6..53c3fe1 100644 (file)
@@ -4,7 +4,7 @@ obj-y                   := component.o core.o bus.o dd.o syscore.o \
                           driver.o class.o platform.o \
                           cpu.o firmware.o init.o map.o devres.o \
                           attribute_container.o transport_class.o \
-                          topology.o container.o
+                          topology.o container.o property.o
 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
 obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y                  += power/
diff --git a/drivers/base/property.c b/drivers/base/property.c
new file mode 100644 (file)
index 0000000..c458458
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * property.c - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *          Mika Westerberg <mika.westerberg@linux.intel.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.
+ */
+
+#include <linux/property.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+
+/**
+ * device_property_present - check if a property of a device is present
+ * @dev: Device whose property is being checked
+ * @propname: Name of the property
+ *
+ * Check if property @propname is present in the device firmware description.
+ */
+bool device_property_present(struct device *dev, const char *propname)
+{
+       if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+               return of_property_read_bool(dev->of_node, propname);
+
+       return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+}
+EXPORT_SYMBOL_GPL(device_property_present);
+
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ * @fwnode: Firmware node whose property to check
+ * @propname: Name of the property
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+       if (is_of_node(fwnode))
+               return of_property_read_bool(of_node(fwnode), propname);
+       else if (is_acpi_node(fwnode))
+               return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
+
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+       (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+             : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
+#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
+       IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
+               (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
+                                       _val_, _nval_)) : \
+               acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
+                                  _proptype_, _val_, _nval_)
+
+/**
+ * device_property_read_u8_array - return a u8 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u8 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u8_array(struct device *dev, const char *propname,
+                                 u8 *val, size_t nval)
+{
+       return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8_array);
+
+/**
+ * device_property_read_u16_array - return a u16 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u16 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u16_array(struct device *dev, const char *propname,
+                                  u16 *val, size_t nval)
+{
+       return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16_array);
+
+/**
+ * device_property_read_u32_array - return a u32 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u32 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u32_array(struct device *dev, const char *propname,
+                                  u32 *val, size_t nval)
+{
+       return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32_array);
+
+/**
+ * device_property_read_u64_array - return a u64 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u64 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u64_array(struct device *dev, const char *propname,
+                                  u64 *val, size_t nval)
+{
+       return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64_array);
+
+/**
+ * device_property_read_string_array - return a string array property of device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of string properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO or %-EILSEQ if the property is not an array of strings,
+ *        %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_string_array(struct device *dev, const char *propname,
+                                     const char **val, size_t nval)
+{
+       return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+               of_property_read_string_array(dev->of_node, propname, val, nval) :
+               acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+                                  DEV_PROP_STRING, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
+/**
+ * device_property_read_string - return a string property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO or %-EILSEQ if the property type is not a string.
+ */
+int device_property_read_string(struct device *dev, const char *propname,
+                               const char **val)
+{
+       return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+               of_property_read_string(dev->of_node, propname, val) :
+               acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+                                  DEV_PROP_STRING, val, 1);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string);
+
+#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
+({ \
+       int _ret_; \
+       if (is_of_node(_fwnode_)) \
+               _ret_ = OF_DEV_PROP_READ_ARRAY(of_node(_fwnode_), _propname_, \
+                                              _type_, _val_, _nval_); \
+       else if (is_acpi_node(_fwnode_)) \
+               _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
+                                          _proptype_, _val_, _nval_); \
+       else \
+               _ret_ = -ENXIO; \
+       _ret_; \
+})
+
+/**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u8 properties with @propname from @fwnode and stores them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+                                 const char *propname, u8 *val, size_t nval)
+{
+       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
+                                     val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+/**
+ * fwnode_property_read_u16_array - return a u16 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u16 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+                                  const char *propname, u16 *val, size_t nval)
+{
+       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
+                                     val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+/**
+ * fwnode_property_read_u32_array - return a u32 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u32 properties with @propname from @fwnode store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+                                  const char *propname, u32 *val, size_t nval)
+{
+       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
+                                     val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+/**
+ * fwnode_property_read_u64_array - return a u64 array property firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u64 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of numbers,
+ *        %-EOVERFLOW if the size of the property is not as expected,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+                                  const char *propname, u64 *val, size_t nval)
+{
+       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
+                                     val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+/**
+ * fwnode_property_read_string_array - return string array property of a node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an string list property @propname from the given firmware node and store
+ * them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO if the property is not an array of strings,
+ *        %-EOVERFLOW if the size of the property is not as expected,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+                                     const char *propname, const char **val,
+                                     size_t nval)
+{
+       if (is_of_node(fwnode))
+               return of_property_read_string_array(of_node(fwnode), propname,
+                                                    val, nval);
+       else if (is_acpi_node(fwnode))
+               return acpi_dev_prop_read(acpi_node(fwnode), propname,
+                                         DEV_PROP_STRING, val, nval);
+
+       return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+
+/**
+ * fwnode_property_read_string - return a string property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found.  The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ *        %-EINVAL if given arguments are not valid,
+ *        %-ENODATA if the property does not have a value,
+ *        %-EPROTO or %-EILSEQ if the property is not a string,
+ *        %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+                               const char *propname, const char **val)
+{
+       if (is_of_node(fwnode))
+               return of_property_read_string(of_node(fwnode),propname, val);
+       else if (is_acpi_node(fwnode))
+               return acpi_dev_prop_read(acpi_node(fwnode), propname,
+                                         DEV_PROP_STRING, val, 1);
+
+       return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+                                                struct fwnode_handle *child)
+{
+       if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+               struct device_node *node;
+
+               node = of_get_next_available_child(dev->of_node, of_node(child));
+               if (node)
+                       return &node->fwnode;
+       } else if (IS_ENABLED(CONFIG_ACPI)) {
+               struct acpi_device *node;
+
+               node = acpi_get_next_child(dev, acpi_node(child));
+               if (node)
+                       return acpi_fwnode_handle(node);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * fwnode_handle_put - Drop reference to a device node
+ * @fwnode: Pointer to the device node to drop the reference to.
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
+       if (is_of_node(fwnode))
+               of_node_put(of_node(fwnode));
+}
+EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+       struct fwnode_handle *child;
+       unsigned int count = 0;
+
+       device_for_each_child_node(dev, child)
+               count++;
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
index 2447221..3804785 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include "../dmaengine.h"
 #include "internal.h"
@@ -1504,6 +1505,9 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        dw->regs = chip->regs;
        chip->dw = dw;
 
+       pm_runtime_enable(chip->dev);
+       pm_runtime_get_sync(chip->dev);
+
        dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
        autocfg = dw_params >> DW_PARAMS_EN & 0x1;
 
@@ -1667,11 +1671,14 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
                 nr_channels);
 
+       pm_runtime_put_sync_suspend(chip->dev);
+
        return 0;
 
 err_dma_register:
        free_irq(chip->irq, dw);
 err_pdata:
+       pm_runtime_put_sync_suspend(chip->dev);
        return err;
 }
 EXPORT_SYMBOL_GPL(dw_dma_probe);
@@ -1681,6 +1688,8 @@ int dw_dma_remove(struct dw_dma_chip *chip)
        struct dw_dma           *dw = chip->dw;
        struct dw_dma_chan      *dwc, *_dwc;
 
+       pm_runtime_get_sync(chip->dev);
+
        dw_dma_off(dw);
        dma_async_device_unregister(&dw->dma);
 
@@ -1693,6 +1702,8 @@ int dw_dma_remove(struct dw_dma_chip *chip)
                channel_clear_bit(dw, CH_EN, dwc->mask);
        }
 
+       pm_runtime_put_sync_suspend(chip->dev);
+       pm_runtime_disable(chip->dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(dw_dma_remove);
index 954b9f6..13dbd3d 100644 (file)
@@ -108,6 +108,38 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
 }
 EXPORT_SYMBOL(__devm_gpiod_get_index);
 
+/**
+ * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
+ * @dev:       GPIO consumer
+ * @child:     firmware node (child of @dev)
+ *
+ * GPIO descriptors returned from this function are automatically disposed on
+ * driver detach.
+ */
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+                                           struct fwnode_handle *child)
+{
+       struct gpio_desc **dr;
+       struct gpio_desc *desc;
+
+       dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
+                         GFP_KERNEL);
+       if (!dr)
+               return ERR_PTR(-ENOMEM);
+
+       desc = fwnode_get_named_gpiod(child, "gpios");
+       if (IS_ERR(desc)) {
+               devres_free(dr);
+               return desc;
+       }
+
+       *dr = desc;
+       devres_add(dev, dr);
+
+       return desc;
+}
+EXPORT_SYMBOL(devm_get_gpiod_from_child);
+
 /**
  * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
  * @dev: GPIO consumer
index 41e91d7..99720c8 100644 (file)
 
 #include <linux/gpio.h>
 
-static DEFINE_SPINLOCK(gpio_lock);
-
-#define CGEN   (0x00)
-#define CGIO   (0x04)
-#define CGLV   (0x08)
-
-#define RGEN   (0x20)
-#define RGIO   (0x24)
-#define RGLV   (0x28)
-
-static unsigned short gpio_ba;
-
-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned  gpio_num)
-{
-       u8 curr_dirs;
-       unsigned short offset, bit;
-
-       spin_lock(&gpio_lock);
-
-       offset = CGIO + gpio_num / 8;
-       bit = gpio_num % 8;
-
-       curr_dirs = inb(gpio_ba + offset);
-
-       if (!(curr_dirs & (1 << bit)))
-               outb(curr_dirs | (1 << bit), gpio_ba + offset);
+#define GEN    0x00
+#define GIO    0x04
+#define GLV    0x08
+
+struct sch_gpio {
+       struct gpio_chip chip;
+       spinlock_t lock;
+       unsigned short iobase;
+       unsigned short core_base;
+       unsigned short resume_base;
+};
 
-       spin_unlock(&gpio_lock);
-       return 0;
-}
+#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip)
 
-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
+static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+                               unsigned reg)
 {
-       int res;
-       unsigned short offset, bit;
+       unsigned base = 0;
 
-       offset = CGLV + gpio_num / 8;
-       bit = gpio_num % 8;
+       if (gpio >= sch->resume_base) {
+               gpio -= sch->resume_base;
+               base += 0x20;
+       }
 
-       res = !!(inb(gpio_ba + offset) & (1 << bit));
-       return res;
+       return base + reg + gpio / 8;
 }
 
-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
 {
-       u8 curr_vals;
-       unsigned short offset, bit;
-
-       spin_lock(&gpio_lock);
-
-       offset = CGLV + gpio_num / 8;
-       bit = gpio_num % 8;
-
-       curr_vals = inb(gpio_ba + offset);
-
-       if (val)
-               outb(curr_vals | (1 << bit), gpio_ba + offset);
-       else
-               outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
-       spin_unlock(&gpio_lock);
+       if (gpio >= sch->resume_base)
+               gpio -= sch->resume_base;
+       return gpio % 8;
 }
 
-static int sch_gpio_core_direction_out(struct gpio_chip *gc,
-                                       unsigned gpio_num, int val)
+static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
 {
-       u8 curr_dirs;
        unsigned short offset, bit;
+       u8 enable;
 
-       spin_lock(&gpio_lock);
+       spin_lock(&sch->lock);
 
-       offset = CGIO + gpio_num / 8;
-       bit = gpio_num % 8;
-
-       curr_dirs = inb(gpio_ba + offset);
-       if (curr_dirs & (1 << bit))
-               outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+       offset = sch_gpio_offset(sch, gpio, GEN);
+       bit = sch_gpio_bit(sch, gpio);
 
-       spin_unlock(&gpio_lock);
+       enable = inb(sch->iobase + offset);
+       if (!(enable & (1 << bit)))
+               outb(enable | (1 << bit), sch->iobase + offset);
 
-       /*
-        * according to the datasheet, writing to the level register has no
-        * effect when GPIO is programmed as input.
-        * Actually the the level register is read-only when configured as input.
-        * Thus presetting the output level before switching to output is _NOT_ possible.
-        * Hence we set the level after configuring the GPIO as output.
-        * But we cannot prevent a short low pulse if direction is set to high
-        * and an external pull-up is connected.
-        */
-       sch_gpio_core_set(gc, gpio_num, val);
-       return 0;
+       spin_unlock(&sch->lock);
 }
 
-static struct gpio_chip sch_gpio_core = {
-       .label                  = "sch_gpio_core",
-       .owner                  = THIS_MODULE,
-       .direction_input        = sch_gpio_core_direction_in,
-       .get                    = sch_gpio_core_get,
-       .direction_output       = sch_gpio_core_direction_out,
-       .set                    = sch_gpio_core_set,
-};
-
-static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
-                                       unsigned gpio_num)
+static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned  gpio_num)
 {
+       struct sch_gpio *sch = to_sch_gpio(gc);
        u8 curr_dirs;
        unsigned short offset, bit;
 
-       spin_lock(&gpio_lock);
+       spin_lock(&sch->lock);
 
-       offset = RGIO + gpio_num / 8;
-       bit = gpio_num % 8;
+       offset = sch_gpio_offset(sch, gpio_num, GIO);
+       bit = sch_gpio_bit(sch, gpio_num);
 
-       curr_dirs = inb(gpio_ba + offset);
+       curr_dirs = inb(sch->iobase + offset);
 
        if (!(curr_dirs & (1 << bit)))
-               outb(curr_dirs | (1 << bit), gpio_ba + offset);
+               outb(curr_dirs | (1 << bit), sch->iobase + offset);
 
-       spin_unlock(&gpio_lock);
+       spin_unlock(&sch->lock);
        return 0;
 }
 
-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
+static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
 {
+       struct sch_gpio *sch = to_sch_gpio(gc);
+       int res;
        unsigned short offset, bit;
 
-       offset = RGLV + gpio_num / 8;
-       bit = gpio_num % 8;
+       offset = sch_gpio_offset(sch, gpio_num, GLV);
+       bit = sch_gpio_bit(sch, gpio_num);
+
+       res = !!(inb(sch->iobase + offset) & (1 << bit));
 
-       return !!(inb(gpio_ba + offset) & (1 << bit));
+       return res;
 }
 
-static void sch_gpio_resume_set(struct gpio_chip *gc,
-                               unsigned gpio_num, int val)
+static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
 {
+       struct sch_gpio *sch = to_sch_gpio(gc);
        u8 curr_vals;
        unsigned short offset, bit;
 
-       spin_lock(&gpio_lock);
+       spin_lock(&sch->lock);
 
-       offset = RGLV + gpio_num / 8;
-       bit = gpio_num % 8;
+       offset = sch_gpio_offset(sch, gpio_num, GLV);
+       bit = sch_gpio_bit(sch, gpio_num);
 
-       curr_vals = inb(gpio_ba + offset);
+       curr_vals = inb(sch->iobase + offset);
 
        if (val)
-               outb(curr_vals | (1 << bit), gpio_ba + offset);
+               outb(curr_vals | (1 << bit), sch->iobase + offset);
        else
-               outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+               outb((curr_vals & ~(1 << bit)), sch->iobase + offset);
 
-       spin_unlock(&gpio_lock);
+       spin_unlock(&sch->lock);
 }
 
-static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
-                                       unsigned gpio_num, int val)
+static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+                                 int val)
 {
+       struct sch_gpio *sch = to_sch_gpio(gc);
        u8 curr_dirs;
        unsigned short offset, bit;
 
-       offset = RGIO + gpio_num / 8;
-       bit = gpio_num % 8;
+       spin_lock(&sch->lock);
 
-       spin_lock(&gpio_lock);
+       offset = sch_gpio_offset(sch, gpio_num, GIO);
+       bit = sch_gpio_bit(sch, gpio_num);
 
-       curr_dirs = inb(gpio_ba + offset);
+       curr_dirs = inb(sch->iobase + offset);
        if (curr_dirs & (1 << bit))
-               outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+               outb(curr_dirs & ~(1 << bit), sch->iobase + offset);
 
-       spin_unlock(&gpio_lock);
+       spin_unlock(&sch->lock);
 
        /*
-       * according to the datasheet, writing to the level register has no
-       * effect when GPIO is programmed as input.
-       * Actually the the level register is read-only when configured as input.
-       * Thus presetting the output level before switching to output is _NOT_ possible.
-       * Hence we set the level after configuring the GPIO as output.
-       * But we cannot prevent a short low pulse if direction is set to high
-       * and an external pull-up is connected.
-       */
-       sch_gpio_resume_set(gc, gpio_num, val);
+        * according to the datasheet, writing to the level register has no
+        * effect when GPIO is programmed as input.
+        * Actually the the level register is read-only when configured as input.
+        * Thus presetting the output level before switching to output is _NOT_ possible.
+        * Hence we set the level after configuring the GPIO as output.
+        * But we cannot prevent a short low pulse if direction is set to high
+        * and an external pull-up is connected.
+        */
+       sch_gpio_set(gc, gpio_num, val);
        return 0;
 }
 
-static struct gpio_chip sch_gpio_resume = {
-       .label                  = "sch_gpio_resume",
+static struct gpio_chip sch_gpio_chip = {
+       .label                  = "sch_gpio",
        .owner                  = THIS_MODULE,
-       .direction_input        = sch_gpio_resume_direction_in,
-       .get                    = sch_gpio_resume_get,
-       .direction_output       = sch_gpio_resume_direction_out,
-       .set                    = sch_gpio_resume_set,
+       .direction_input        = sch_gpio_direction_in,
+       .get                    = sch_gpio_get,
+       .direction_output       = sch_gpio_direction_out,
+       .set                    = sch_gpio_set,
 };
 
 static int sch_gpio_probe(struct platform_device *pdev)
 {
+       struct sch_gpio *sch;
        struct resource *res;
-       int err, id;
 
-       id = pdev->id;
-       if (!id)
-               return -ENODEV;
+       sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
+       if (!sch)
+               return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!res)
                return -EBUSY;
 
-       if (!request_region(res->start, resource_size(res), pdev->name))
+       if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
+                                pdev->name))
                return -EBUSY;
 
-       gpio_ba = res->start;
+       spin_lock_init(&sch->lock);
+       sch->iobase = res->start;
+       sch->chip = sch_gpio_chip;
+       sch->chip.label = dev_name(&pdev->dev);
+       sch->chip.dev = &pdev->dev;
 
-       switch (id) {
+       switch (pdev->id) {
        case PCI_DEVICE_ID_INTEL_SCH_LPC:
-               sch_gpio_core.base = 0;
-               sch_gpio_core.ngpio = 10;
-               sch_gpio_resume.base = 10;
-               sch_gpio_resume.ngpio = 4;
+               sch->core_base = 0;
+               sch->resume_base = 10;
+               sch->chip.ngpio = 14;
+
                /*
                 * GPIO[6:0] enabled by default
                 * GPIO7 is configured by the CMC as SLPIOVR
                 * Enable GPIO[9:8] core powered gpios explicitly
                 */
-               outb(0x3, gpio_ba + CGEN + 1);
+               sch_gpio_enable(sch, 8);
+               sch_gpio_enable(sch, 9);
                /*
                 * SUS_GPIO[2:0] enabled by default
                 * Enable SUS_GPIO3 resume powered gpio explicitly
                 */
-               outb(0x8, gpio_ba + RGEN);
+               sch_gpio_enable(sch, 13);
                break;
 
        case PCI_DEVICE_ID_INTEL_ITC_LPC:
-               sch_gpio_core.base = 0;
-               sch_gpio_core.ngpio = 5;
-               sch_gpio_resume.base = 5;
-               sch_gpio_resume.ngpio = 9;
+               sch->core_base = 0;
+               sch->resume_base = 5;
+               sch->chip.ngpio = 14;
                break;
 
        case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
-               sch_gpio_core.base = 0;
-               sch_gpio_core.ngpio = 21;
-               sch_gpio_resume.base = 21;
-               sch_gpio_resume.ngpio = 9;
+               sch->core_base = 0;
+               sch->resume_base = 21;
+               sch->chip.ngpio = 30;
                break;
 
        default:
-               err = -ENODEV;
-               goto err_sch_gpio_core;
+               return -ENODEV;
        }
 
-       sch_gpio_core.dev = &pdev->dev;
-       sch_gpio_resume.dev = &pdev->dev;
-
-       err = gpiochip_add(&sch_gpio_core);
-       if (err < 0)
-               goto err_sch_gpio_core;
+       platform_set_drvdata(pdev, sch);
 
-       err = gpiochip_add(&sch_gpio_resume);
-       if (err < 0)
-               goto err_sch_gpio_resume;
-
-       return 0;
-
-err_sch_gpio_resume:
-       gpiochip_remove(&sch_gpio_core);
-
-err_sch_gpio_core:
-       release_region(res->start, resource_size(res));
-       gpio_ba = 0;
-
-       return err;
+       return gpiochip_add(&sch->chip);
 }
 
 static int sch_gpio_remove(struct platform_device *pdev)
 {
-       struct resource *res;
-       if (gpio_ba) {
-
-               gpiochip_remove(&sch_gpio_core);
-               gpiochip_remove(&sch_gpio_resume);
-
-               res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-
-               release_region(res->start, resource_size(res));
-               gpio_ba = 0;
-       }
+       struct sch_gpio *sch = platform_get_drvdata(pdev);
 
+       gpiochip_remove(&sch->chip);
        return 0;
 }
 
index 05c6275..ba98bb5 100644 (file)
@@ -287,9 +287,45 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
        }
 }
 
+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;
 };
@@ -303,13 +339,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
 
        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;
@@ -317,40 +364,79 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
 
 /**
  * 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);
@@ -359,8 +445,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
 
        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);
 }
index e8e98ca..58659db 100644 (file)
@@ -1505,14 +1505,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
                                        unsigned int idx,
                                        enum gpio_lookup_flags *flags)
 {
+       static const char * const suffixes[] = { "gpios", "gpio" };
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_gpio_info info;
        struct gpio_desc *desc;
+       char propname[32];
+       int i;
 
-       desc = acpi_get_gpiod_by_index(dev, idx, &info);
-       if (IS_ERR(desc))
-               return desc;
+       /* Try first from _DSD */
+       for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+               if (con_id && strcmp(con_id, "gpios")) {
+                       snprintf(propname, sizeof(propname), "%s-%s",
+                                con_id, suffixes[i]);
+               } else {
+                       snprintf(propname, sizeof(propname), "%s",
+                                suffixes[i]);
+               }
+
+               desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
+               if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+                       break;
+       }
 
-       if (info.gpioint && info.active_low)
+       /* Then from plain _CRS GPIOs */
+       if (IS_ERR(desc)) {
+               desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
+               if (IS_ERR(desc))
+                       return desc;
+       }
+
+       if (info.active_low)
                *flags |= GPIO_ACTIVE_LOW;
 
        return desc;
@@ -1712,6 +1734,61 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__gpiod_get_index);
 
+/**
+ * fwnode_get_named_gpiod - obtain a GPIO from firmware node
+ * @fwnode:    handle of the firmware node
+ * @propname:  name of the firmware property representing the GPIO
+ *
+ * This function can be used for drivers that get their configuration
+ * from firmware.
+ *
+ * Function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+                                        const char *propname)
+{
+       struct gpio_desc *desc = ERR_PTR(-ENODEV);
+       bool active_low = false;
+       int ret;
+
+       if (!fwnode)
+               return ERR_PTR(-EINVAL);
+
+       if (is_of_node(fwnode)) {
+               enum of_gpio_flags flags;
+
+               desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0,
+                                               &flags);
+               if (!IS_ERR(desc))
+                       active_low = flags & OF_GPIO_ACTIVE_LOW;
+       } else if (is_acpi_node(fwnode)) {
+               struct acpi_gpio_info info;
+
+               desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
+                                              &info);
+               if (!IS_ERR(desc))
+                       active_low = info.active_low;
+       }
+
+       if (IS_ERR(desc))
+               return desc;
+
+       ret = gpiod_request(desc, NULL);
+       if (ret)
+               return ERR_PTR(ret);
+
+       /* Only value flag can be set from both DT and ACPI is active_low */
+       if (active_low)
+               set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+       return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
+
 /**
  * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
  *                            function
index 9db2b6a..e3a5211 100644 (file)
@@ -34,7 +34,8 @@ 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 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);
 #else
 static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
@@ -47,8 +48,8 @@ static inline void
 acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
 
 static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct device *dev, int index,
-                       struct acpi_gpio_info *info)
+acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
+                       int index, struct acpi_gpio_info *info)
 {
        return ERR_PTR(-ENOSYS);
 }
index 8bcdb98..9cb5c95 100644 (file)
@@ -4325,7 +4325,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
                ironlake_fdi_disable(crtc);
 
                ironlake_disable_pch_transcoder(dev_priv, pipe);
-               intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
 
                if (HAS_PCH_CPT(dev)) {
                        /* disable TRANS_DP_CTL */
@@ -4389,7 +4388,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
 
        if (intel_crtc->config.has_pch_encoder) {
                lpt_disable_pch_transcoder(dev_priv);
-               intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
                intel_ddi_fdi_disable(crtc);
        }
 
index a6bd142..c0bbf21 100644 (file)
@@ -899,6 +899,17 @@ void intel_lvds_init(struct drm_device *dev)
        int pipe;
        u8 pin;
 
+       /*
+        * Unlock registers and just leave them unlocked. Do this before
+        * checking quirk lists to avoid bogus WARNINGs.
+        */
+       if (HAS_PCH_SPLIT(dev)) {
+               I915_WRITE(PCH_PP_CONTROL,
+                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+       } else {
+               I915_WRITE(PP_CONTROL,
+                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+       }
        if (!intel_lvds_supported(dev))
                return;
 
@@ -1097,17 +1108,6 @@ out:
        lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) &
                                 LVDS_A3_POWER_MASK;
 
-       /*
-        * Unlock registers and just
-        * leave them unlocked
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_PP_CONTROL,
-                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
-       } else {
-               I915_WRITE(PP_CONTROL,
-                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
-       }
        lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
        if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
                DRM_DEBUG_KMS("lid notifier registration failed\n");
index cd05677..72a40f9 100644 (file)
@@ -218,7 +218,6 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-               device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
index 5ae6a43..1931057 100644 (file)
@@ -551,8 +551,8 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
                        }
 
                        if (status & 0x40000000) {
-                               nouveau_fifo_uevent(&priv->base);
                                nv_wr32(priv, 0x002100, 0x40000000);
+                               nouveau_fifo_uevent(&priv->base);
                                status &= ~0x40000000;
                        }
                }
index 1fe1f8f..074d434 100644 (file)
@@ -740,6 +740,8 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
        u32 inte = nv_rd32(priv, 0x002628);
        u32 unkn;
 
+       nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
+
        for (unkn = 0; unkn < 8; unkn++) {
                u32 ints = (intr >> (unkn * 0x04)) & inte;
                if (ints & 0x1) {
@@ -751,8 +753,6 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
                        nv_mask(priv, 0x002628, ints, 0);
                }
        }
-
-       nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
 }
 
 static void
index d2f0fd3..f8734eb 100644 (file)
@@ -952,8 +952,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
        }
 
        if (stat & 0x80000000) {
-               nve0_fifo_intr_engine(priv);
                nv_wr32(priv, 0x002100, 0x80000000);
+               nve0_fifo_intr_engine(priv);
                stat &= ~0x80000000;
        }
 
index 5723807..62b97c4 100644 (file)
@@ -629,7 +629,6 @@ int nouveau_pmops_suspend(struct device *dev)
 
        pci_save_state(pdev);
        pci_disable_device(pdev);
-       pci_ignore_hotplug(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
        return 0;
 }
@@ -933,6 +932,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
        ret = nouveau_do_suspend(drm_dev, true);
        pci_save_state(pdev);
        pci_disable_device(pdev);
+       pci_ignore_hotplug(pdev);
        pci_set_power_state(pdev, PCI_D3cold);
        drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
        return ret;
index 515cd9a..f32a434 100644 (file)
@@ -52,20 +52,24 @@ nouveau_fctx(struct nouveau_fence *fence)
        return container_of(fence->base.lock, struct nouveau_fence_chan, lock);
 }
 
-static void
+static int
 nouveau_fence_signal(struct nouveau_fence *fence)
 {
+       int drop = 0;
+
        fence_signal_locked(&fence->base);
        list_del(&fence->head);
+       rcu_assign_pointer(fence->channel, NULL);
 
        if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) {
                struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
 
                if (!--fctx->notify_ref)
-                       nvif_notify_put(&fctx->notify);
+                       drop = 1;
        }
 
        fence_put(&fence->base);
+       return drop;
 }
 
 static struct nouveau_fence *
@@ -88,16 +92,23 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
 {
        struct nouveau_fence *fence;
 
-       nvif_notify_fini(&fctx->notify);
-
        spin_lock_irq(&fctx->lock);
        while (!list_empty(&fctx->pending)) {
                fence = list_entry(fctx->pending.next, typeof(*fence), head);
 
-               nouveau_fence_signal(fence);
-               fence->channel = NULL;
+               if (nouveau_fence_signal(fence))
+                       nvif_notify_put(&fctx->notify);
        }
        spin_unlock_irq(&fctx->lock);
+
+       nvif_notify_fini(&fctx->notify);
+       fctx->dead = 1;
+
+       /*
+        * Ensure that all accesses to fence->channel complete before freeing
+        * the channel.
+        */
+       synchronize_rcu();
 }
 
 static void
@@ -112,21 +123,23 @@ nouveau_fence_context_free(struct nouveau_fence_chan *fctx)
        kref_put(&fctx->fence_ref, nouveau_fence_context_put);
 }
 
-static void
+static int
 nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx)
 {
        struct nouveau_fence *fence;
-
+       int drop = 0;
        u32 seq = fctx->read(chan);
 
        while (!list_empty(&fctx->pending)) {
                fence = list_entry(fctx->pending.next, typeof(*fence), head);
 
                if ((int)(seq - fence->base.seqno) < 0)
-                       return;
+                       break;
 
-               nouveau_fence_signal(fence);
+               drop |= nouveau_fence_signal(fence);
        }
+
+       return drop;
 }
 
 static int
@@ -135,18 +148,21 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify)
        struct nouveau_fence_chan *fctx =
                container_of(notify, typeof(*fctx), notify);
        unsigned long flags;
+       int ret = NVIF_NOTIFY_KEEP;
 
        spin_lock_irqsave(&fctx->lock, flags);
        if (!list_empty(&fctx->pending)) {
                struct nouveau_fence *fence;
+               struct nouveau_channel *chan;
 
                fence = list_entry(fctx->pending.next, typeof(*fence), head);
-               nouveau_fence_update(fence->channel, fctx);
+               chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
+               if (nouveau_fence_update(fence->channel, fctx))
+                       ret = NVIF_NOTIFY_DROP;
        }
        spin_unlock_irqrestore(&fctx->lock, flags);
 
-       /* Always return keep here. NVIF refcount is handled with nouveau_fence_update */
-       return NVIF_NOTIFY_KEEP;
+       return ret;
 }
 
 void
@@ -262,7 +278,10 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
        if (!ret) {
                fence_get(&fence->base);
                spin_lock_irq(&fctx->lock);
-               nouveau_fence_update(chan, fctx);
+
+               if (nouveau_fence_update(chan, fctx))
+                       nvif_notify_put(&fctx->notify);
+
                list_add_tail(&fence->head, &fctx->pending);
                spin_unlock_irq(&fctx->lock);
        }
@@ -276,13 +295,16 @@ nouveau_fence_done(struct nouveau_fence *fence)
        if (fence->base.ops == &nouveau_fence_ops_legacy ||
            fence->base.ops == &nouveau_fence_ops_uevent) {
                struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
+               struct nouveau_channel *chan;
                unsigned long flags;
 
                if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags))
                        return true;
 
                spin_lock_irqsave(&fctx->lock, flags);
-               nouveau_fence_update(fence->channel, fctx);
+               chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock));
+               if (chan && nouveau_fence_update(chan, fctx))
+                       nvif_notify_put(&fctx->notify);
                spin_unlock_irqrestore(&fctx->lock, flags);
        }
        return fence_is_signaled(&fence->base);
@@ -387,12 +409,18 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
 
        if (fence && (!exclusive || !fobj || !fobj->shared_count)) {
                struct nouveau_channel *prev = NULL;
+               bool must_wait = true;
 
                f = nouveau_local_fence(fence, chan->drm);
-               if (f)
-                       prev = f->channel;
+               if (f) {
+                       rcu_read_lock();
+                       prev = rcu_dereference(f->channel);
+                       if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0))
+                               must_wait = false;
+                       rcu_read_unlock();
+               }
 
-               if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
+               if (must_wait)
                        ret = fence_wait(fence, intr);
 
                return ret;
@@ -403,19 +431,22 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
 
        for (i = 0; i < fobj->shared_count && !ret; ++i) {
                struct nouveau_channel *prev = NULL;
+               bool must_wait = true;
 
                fence = rcu_dereference_protected(fobj->shared[i],
                                                reservation_object_held(resv));
 
                f = nouveau_local_fence(fence, chan->drm);
-               if (f)
-                       prev = f->channel;
+               if (f) {
+                       rcu_read_lock();
+                       prev = rcu_dereference(f->channel);
+                       if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0))
+                               must_wait = false;
+                       rcu_read_unlock();
+               }
 
-               if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan))))
+               if (must_wait)
                        ret = fence_wait(fence, intr);
-
-               if (ret)
-                       break;
        }
 
        return ret;
@@ -463,7 +494,7 @@ static const char *nouveau_fence_get_timeline_name(struct fence *f)
        struct nouveau_fence *fence = from_fence(f);
        struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
 
-       return fence->channel ? fctx->name : "dead channel";
+       return !fctx->dead ? fctx->name : "dead channel";
 }
 
 /*
@@ -476,9 +507,16 @@ static bool nouveau_fence_is_signaled(struct fence *f)
 {
        struct nouveau_fence *fence = from_fence(f);
        struct nouveau_fence_chan *fctx = nouveau_fctx(fence);
-       struct nouveau_channel *chan = fence->channel;
+       struct nouveau_channel *chan;
+       bool ret = false;
+
+       rcu_read_lock();
+       chan = rcu_dereference(fence->channel);
+       if (chan)
+               ret = (int)(fctx->read(chan) - fence->base.seqno) >= 0;
+       rcu_read_unlock();
 
-       return (int)(fctx->read(chan) - fence->base.seqno) >= 0;
+       return ret;
 }
 
 static bool nouveau_fence_no_signaling(struct fence *f)
index 943b0b1..96e461c 100644 (file)
@@ -14,7 +14,7 @@ struct nouveau_fence {
 
        bool sysmem;
 
-       struct nouveau_channel *channel;
+       struct nouveau_channel __rcu *channel;
        unsigned long timeout;
 };
 
@@ -47,7 +47,7 @@ struct nouveau_fence_chan {
        char name[32];
 
        struct nvif_notify notify;
-       int notify_ref;
+       int notify_ref, dead;
 };
 
 struct nouveau_fence_priv {
index a3e7aed..6f377de 100644 (file)
@@ -251,22 +251,19 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
 
 static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
 {
-       int i, r = 0;
+       struct radeon_cs_reloc *reloc;
+       int r;
 
-       for (i = 0; i < p->nrelocs; i++) {
+       list_for_each_entry(reloc, &p->validated, tv.head) {
                struct reservation_object *resv;
 
-               if (!p->relocs[i].robj)
-                       continue;
-
-               resv = p->relocs[i].robj->tbo.resv;
+               resv = reloc->robj->tbo.resv;
                r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv,
-                                              p->relocs[i].tv.shared);
-
+                                              reloc->tv.shared);
                if (r)
-                       break;
+                       return r;
        }
-       return r;
+       return 0;
 }
 
 /* XXX: note that this is called from the legacy UMS CS ioctl as well */
index 8309b11..0358676 100644 (file)
@@ -795,6 +795,8 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
 
        /* Get associated drm_crtc: */
        drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
+       if (!drmcrtc)
+               return -EINVAL;
 
        /* Helper routine in DRM core does all the work: */
        return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
index 99a960a..4c0d786 100644 (file)
@@ -213,6 +213,13 @@ int radeon_bo_create(struct radeon_device *rdev,
        if (!(rdev->flags & RADEON_IS_PCIE))
                bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
 
+#ifdef CONFIG_X86_32
+       /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
+        * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
+        */
+       bo->flags &= ~RADEON_GEM_GTT_WC;
+#endif
+
        radeon_ttm_placement_from_domain(bo, domain);
        /* Kernel allocation are uninterruptible */
        down_read(&rdev->pm.mclk_lock);
index 63f3f03..c604f4c 100644 (file)
 #define CDNS_I2C_DIVA_MAX      4
 #define CDNS_I2C_DIVB_MAX      64
 
+#define CDNS_I2C_TIMEOUT_MAX   0xFF
+
 #define cdns_i2c_readreg(offset)       readl_relaxed(id->membase + offset)
 #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
 
@@ -852,6 +854,15 @@ static int cdns_i2c_probe(struct platform_device *pdev)
                goto err_clk_dis;
        }
 
+       /*
+        * Cadence I2C controller has a bug wherein it generates
+        * invalid read transaction after HW timeout in master receiver mode.
+        * HW timeout is not used by this driver and the interrupt is disabled.
+        * But the feature itself cannot be disabled. Hence maximum value
+        * is written to this register to reduce the chances of error.
+        */
+       cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+
        dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
                 id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
 
index d15b7c9..01f0cd8 100644 (file)
@@ -407,11 +407,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
        if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
                if (msg->flags & I2C_M_IGNORE_NAK)
                        return msg->len;
-               if (stop) {
-                       w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
-                       w |= DAVINCI_I2C_MDR_STP;
-                       davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
-               }
+               w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+               w |= DAVINCI_I2C_MDR_STP;
+               davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
                return -EREMOTEIO;
        }
        return -EIO;
index edca99d..23628b7 100644 (file)
@@ -359,7 +359,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        }
 
        /* Configure Tx/Rx FIFO threshold levels */
-       dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+       dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
        dw_writel(dev, 0, DW_IC_RX_TL);
 
        /* configure the i2c master */
index 26942c1..277a228 100644 (file)
@@ -922,14 +922,12 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
                if (stat & OMAP_I2C_STAT_NACK) {
                        err |= OMAP_I2C_STAT_NACK;
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
-                       break;
                }
 
                if (stat & OMAP_I2C_STAT_AL) {
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL);
-                       break;
                }
 
                /*
@@ -954,11 +952,13 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
                        if (dev->fifo_size)
                                num_bytes = dev->buf_len;
 
-                       omap_i2c_receive_data(dev, num_bytes, true);
-
-                       if (dev->errata & I2C_OMAP_ERRATA_I207)
+                       if (dev->errata & I2C_OMAP_ERRATA_I207) {
                                i2c_omap_errata_i207(dev, stat);
+                               num_bytes = (omap_i2c_read_reg(dev,
+                                       OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F;
+                       }
 
+                       omap_i2c_receive_data(dev, num_bytes, true);
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
                        continue;
                }
index f43b4e1..68aeb8e 100644 (file)
@@ -403,6 +403,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
                return -ENOMEM;
        }
 
+       acpi_walk_dep_device_list(handle);
        return 0;
 }
 
index 88bdc8f..bc4e787 100644 (file)
@@ -127,6 +127,14 @@ config AT91_ADC
        help
          Say yes here to build support for Atmel AT91 ADC.
 
+config AXP288_ADC
+       tristate "X-Powers AXP288 ADC driver"
+       depends on MFD_AXP20X
+       help
+         Say yes here to have support for X-Powers power management IC (PMIC) ADC
+         device. Depending on platform configuration, this general purpose ADC can
+         be used for sampling sensors such as thermal resistors.
+
 config EXYNOS_ADC
        tristate "Exynos ADC driver support"
        depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
index cb88a6a..f30093f 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
 obj-$(CONFIG_AD7887) += ad7887.o
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1027) += max1027.o
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
new file mode 100644 (file)
index 0000000..08bcfb0
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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 of the License.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/platform_device.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+#define AXP288_ADC_EN_MASK             0xF1
+#define AXP288_ADC_TS_PIN_GPADC                0xF2
+#define AXP288_ADC_TS_PIN_ON           0xF3
+
+enum axp288_adc_id {
+       AXP288_ADC_TS,
+       AXP288_ADC_PMIC,
+       AXP288_ADC_GP,
+       AXP288_ADC_BATT_CHRG_I,
+       AXP288_ADC_BATT_DISCHRG_I,
+       AXP288_ADC_BATT_V,
+       AXP288_ADC_NR_CHAN,
+};
+
+struct axp288_adc_info {
+       int irq;
+       struct regmap *regmap;
+};
+
+static const struct iio_chan_spec const axp288_adc_channels[] = {
+       {
+               .indexed = 1,
+               .type = IIO_TEMP,
+               .channel = 0,
+               .address = AXP288_TS_ADC_H,
+               .datasheet_name = "TS_PIN",
+       }, {
+               .indexed = 1,
+               .type = IIO_TEMP,
+               .channel = 1,
+               .address = AXP288_PMIC_ADC_H,
+               .datasheet_name = "PMIC_TEMP",
+       }, {
+               .indexed = 1,
+               .type = IIO_TEMP,
+               .channel = 2,
+               .address = AXP288_GP_ADC_H,
+               .datasheet_name = "GPADC",
+       }, {
+               .indexed = 1,
+               .type = IIO_CURRENT,
+               .channel = 3,
+               .address = AXP20X_BATT_CHRG_I_H,
+               .datasheet_name = "BATT_CHG_I",
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+       }, {
+               .indexed = 1,
+               .type = IIO_CURRENT,
+               .channel = 4,
+               .address = AXP20X_BATT_DISCHRG_I_H,
+               .datasheet_name = "BATT_DISCHRG_I",
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+       }, {
+               .indexed = 1,
+               .type = IIO_VOLTAGE,
+               .channel = 5,
+               .address = AXP20X_BATT_V_H,
+               .datasheet_name = "BATT_V",
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+       },
+};
+
+#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
+               _consumer_channel)                              \
+       {                                                       \
+               .adc_channel_label = _adc_channel_label,        \
+               .consumer_dev_name = _consumer_dev_name,        \
+               .consumer_channel = _consumer_channel,          \
+       }
+
+/* for consumer drivers */
+static struct iio_map axp288_adc_default_maps[] = {
+       AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
+       AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
+       AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
+       AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
+       AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
+       AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
+       {},
+};
+
+static int axp288_adc_read_channel(int *val, unsigned long address,
+                               struct regmap *regmap)
+{
+       u8 buf[2];
+
+       if (regmap_bulk_read(regmap, address, buf, 2))
+               return -EIO;
+       *val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
+
+       return IIO_VAL_INT;
+}
+
+static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
+                               unsigned long address)
+{
+       /* channels other than GPADC do not need to switch TS pin */
+       if (address != AXP288_GP_ADC_H)
+               return 0;
+
+       return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
+}
+
+static int axp288_adc_read_raw(struct iio_dev *indio_dev,
+                       struct iio_chan_spec const *chan,
+                       int *val, int *val2, long mask)
+{
+       int ret;
+       struct axp288_adc_info *info = iio_priv(indio_dev);
+
+       mutex_lock(&indio_dev->mlock);
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
+                                       chan->address)) {
+                       dev_err(&indio_dev->dev, "GPADC mode\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = axp288_adc_read_channel(val, chan->address, info->regmap);
+               if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
+                                               chan->address))
+                       dev_err(&indio_dev->dev, "TS pin restore\n");
+               break;
+       case IIO_CHAN_INFO_PROCESSED:
+               ret = axp288_adc_read_channel(val, chan->address, info->regmap);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static int axp288_adc_set_state(struct regmap *regmap)
+{
+       /* ADC should be always enabled for internal FG to function */
+       if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
+               return -EIO;
+
+       return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
+}
+
+static const struct iio_info axp288_adc_iio_info = {
+       .read_raw = &axp288_adc_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static int axp288_adc_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct axp288_adc_info *info;
+       struct iio_dev *indio_dev;
+       struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       info = iio_priv(indio_dev);
+       info->irq = platform_get_irq(pdev, 0);
+       if (info->irq < 0) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               return info->irq;
+       }
+       platform_set_drvdata(pdev, indio_dev);
+       info->regmap = axp20x->regmap;
+       /*
+        * Set ADC to enabled state at all time, including system suspend.
+        * otherwise internal fuel gauge functionality may be affected.
+        */
+       ret = axp288_adc_set_state(axp20x->regmap);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to enable ADC device\n");
+               return ret;
+       }
+
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->name = pdev->name;
+       indio_dev->channels = axp288_adc_channels;
+       indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
+       indio_dev->info = &axp288_adc_iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
+       if (ret < 0)
+               return ret;
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "unable to register iio device\n");
+               goto err_array_unregister;
+       }
+       return 0;
+
+err_array_unregister:
+       iio_map_array_unregister(indio_dev);
+
+       return ret;
+}
+
+static int axp288_adc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+       iio_device_unregister(indio_dev);
+       iio_map_array_unregister(indio_dev);
+
+       return 0;
+}
+
+static struct platform_device_id axp288_adc_id_table[] = {
+       { .name = "axp288_adc" },
+       {},
+};
+
+static struct platform_driver axp288_adc_driver = {
+       .probe = axp288_adc_probe,
+       .remove = axp288_adc_remove,
+       .id_table = axp288_adc_id_table,
+       .driver = {
+               .name = "axp288_adc",
+       },
+};
+
+MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
+
+module_platform_driver(axp288_adc_driver);
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
+MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
+MODULE_LICENSE("GPL");
index bc20348..8afa28e 100644 (file)
@@ -421,7 +421,7 @@ static int evdev_open(struct inode *inode, struct file *file)
 
  err_free_client:
        evdev_detach_client(evdev, client);
-       kfree(client);
+       kvfree(client);
        return error;
 }
 
index 432d363..c9c1c8c 100644 (file)
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/gpio_keys.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>
 
 #define DRV_NAME       "gpio-keys-polled"
 
@@ -51,15 +50,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
        int state;
 
        if (bdata->can_sleep)
-               state = !!gpio_get_value_cansleep(button->gpio);
+               state = !!gpiod_get_value_cansleep(button->gpiod);
        else
-               state = !!gpio_get_value(button->gpio);
+               state = !!gpiod_get_value(button->gpiod);
 
        if (state != bdata->last_state) {
                unsigned int type = button->type ?: EV_KEY;
 
-               input_event(input, type, button->code,
-                           !!(state ^ button->active_low));
+               input_event(input, type, button->code, state);
                input_sync(input);
                bdata->count = 0;
                bdata->last_state = state;
@@ -102,21 +100,15 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
                pdata->disable(bdev->dev);
 }
 
-#ifdef CONFIG_OF
 static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
 {
-       struct device_node *node, *pp;
        struct gpio_keys_platform_data *pdata;
        struct gpio_keys_button *button;
+       struct fwnode_handle *child;
        int error;
        int nbuttons;
-       int i;
-
-       node = dev->of_node;
-       if (!node)
-               return NULL;
 
-       nbuttons = of_get_child_count(node);
+       nbuttons = device_get_child_node_count(dev);
        if (nbuttons == 0)
                return NULL;
 
@@ -126,52 +118,44 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                return ERR_PTR(-ENOMEM);
 
        pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
-       pdata->nbuttons = nbuttons;
 
-       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
-       of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+       pdata->rep = device_property_present(dev, "autorepeat");
+       device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
 
-       i = 0;
-       for_each_child_of_node(node, pp) {
-               int gpio;
-               enum of_gpio_flags flags;
+       device_for_each_child_node(dev, child) {
+               struct gpio_desc *desc;
 
-               if (!of_find_property(pp, "gpios", NULL)) {
-                       pdata->nbuttons--;
-                       dev_warn(dev, "Found button without gpios\n");
-                       continue;
-               }
-
-               gpio = of_get_gpio_flags(pp, 0, &flags);
-               if (gpio < 0) {
-                       error = gpio;
+               desc = devm_get_gpiod_from_child(dev, child);
+               if (IS_ERR(desc)) {
+                       error = PTR_ERR(desc);
                        if (error != -EPROBE_DEFER)
                                dev_err(dev,
                                        "Failed to get gpio flags, error: %d\n",
                                        error);
+                       fwnode_handle_put(child);
                        return ERR_PTR(error);
                }
 
-               button = &pdata->buttons[i++];
-
-               button->gpio = gpio;
-               button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+               button = &pdata->buttons[pdata->nbuttons++];
+               button->gpiod = desc;
 
-               if (of_property_read_u32(pp, "linux,code", &button->code)) {
-                       dev_err(dev, "Button without keycode: 0x%x\n",
-                               button->gpio);
+               if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
+                       dev_err(dev, "Button without keycode: %d\n",
+                               pdata->nbuttons - 1);
+                       fwnode_handle_put(child);
                        return ERR_PTR(-EINVAL);
                }
 
-               button->desc = of_get_property(pp, "label", NULL);
+               fwnode_property_read_string(child, "label", &button->desc);
 
-               if (of_property_read_u32(pp, "linux,input-type", &button->type))
+               if (fwnode_property_read_u32(child, "linux,input-type",
+                                            &button->type))
                        button->type = EV_KEY;
 
-               button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+               button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");
 
-               if (of_property_read_u32(pp, "debounce-interval",
-                                        &button->debounce_interval))
+               if (fwnode_property_read_u32(child, "debounce-interval",
+                                            &button->debounce_interval))
                        button->debounce_interval = 5;
        }
 
@@ -187,15 +171,6 @@ static const struct of_device_id gpio_keys_polled_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
 
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
-{
-       return NULL;
-}
-#endif
-
 static int gpio_keys_polled_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -259,7 +234,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
        for (i = 0; i < pdata->nbuttons; i++) {
                struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_keys_button_data *bdata = &bdev->data[i];
-               unsigned int gpio = button->gpio;
                unsigned int type = button->type ?: EV_KEY;
 
                if (button->wakeup) {
@@ -267,15 +241,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                        return -EINVAL;
                }
 
-               error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
-                                             button->desc ? : DRV_NAME);
-               if (error) {
-                       dev_err(dev, "unable to claim gpio %u, err=%d\n",
-                               gpio, error);
-                       return error;
+               /*
+                * Legacy GPIO number so request the GPIO here and
+                * convert it to descriptor.
+                */
+               if (!button->gpiod && gpio_is_valid(button->gpio)) {
+                       unsigned flags = 0;
+
+                       if (button->active_low)
+                               flags |= GPIOF_ACTIVE_LOW;
+
+                       error = devm_gpio_request_one(&pdev->dev, button->gpio,
+                                       flags, button->desc ? : DRV_NAME);
+                       if (error) {
+                               dev_err(dev, "unable to claim gpio %u, err=%d\n",
+                                       button->gpio, error);
+                               return error;
+                       }
+
+                       button->gpiod = gpio_to_desc(button->gpio);
                }
 
-               bdata->can_sleep = gpio_cansleep(gpio);
+               if (IS_ERR(button->gpiod))
+                       return PTR_ERR(button->gpiod);
+
+               bdata->can_sleep = gpiod_cansleep(button->gpiod);
                bdata->last_state = -1;
                bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
                                                pdata->poll_interval);
@@ -308,7 +298,7 @@ static struct platform_driver gpio_keys_polled_driver = {
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+               .of_match_table = gpio_keys_polled_of_match,
        },
 };
 module_platform_driver(gpio_keys_polled_driver);
index b4518c8..868e6fc 100644 (file)
  */
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/kernel.h>
 #include <linux/leds.h>
 #include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 
 struct gpio_led_data {
        struct led_classdev cdev;
-       unsigned gpio;
+       struct gpio_desc *gpiod;
        struct work_struct work;
        u8 new_level;
        u8 can_sleep;
-       u8 active_low;
        u8 blinking;
-       int (*platform_gpio_blink_set)(unsigned gpio, int state,
+       int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
                        unsigned long *delay_on, unsigned long *delay_off);
 };
 
@@ -40,12 +38,11 @@ static void gpio_led_work(struct work_struct *work)
                container_of(work, struct gpio_led_data, work);
 
        if (led_dat->blinking) {
-               led_dat->platform_gpio_blink_set(led_dat->gpio,
-                                                led_dat->new_level,
-                                                NULL, NULL);
+               led_dat->platform_gpio_blink_set(led_dat->gpiod,
+                                       led_dat->new_level, NULL, NULL);
                led_dat->blinking = 0;
        } else
-               gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+               gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
 }
 
 static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,9 +57,6 @@ static void gpio_led_set(struct led_classdev *led_cdev,
        else
                level = 1;
 
-       if (led_dat->active_low)
-               level = !level;
-
        /* Setting GPIOs with I2C/etc requires a task context, and we don't
         * seem to have a reliable way to know if we're already in one; so
         * let's just assume the worst.
@@ -72,11 +66,11 @@ static void gpio_led_set(struct led_classdev *led_cdev,
                schedule_work(&led_dat->work);
        } else {
                if (led_dat->blinking) {
-                       led_dat->platform_gpio_blink_set(led_dat->gpio, level,
+                       led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
                                                         NULL, NULL);
                        led_dat->blinking = 0;
                } else
-                       gpio_set_value(led_dat->gpio, level);
+                       gpiod_set_value(led_dat->gpiod, level);
        }
 }
 
@@ -87,34 +81,49 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
                container_of(led_cdev, struct gpio_led_data, cdev);
 
        led_dat->blinking = 1;
-       return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+       return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
                                                delay_on, delay_off);
 }
 
 static int create_gpio_led(const struct gpio_led *template,
        struct gpio_led_data *led_dat, struct device *parent,
-       int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
+       int (*blink_set)(struct gpio_desc *, int, unsigned long *,
+                        unsigned long *))
 {
        int ret, state;
 
-       led_dat->gpio = -1;
+       led_dat->gpiod = template->gpiod;
+       if (!led_dat->gpiod) {
+               /*
+                * This is the legacy code path for platform code that
+                * still uses GPIO numbers. Ultimately we would like to get
+                * rid of this block completely.
+                */
+               unsigned long flags = 0;
+
+               /* skip leds that aren't available */
+               if (!gpio_is_valid(template->gpio)) {
+                       dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
+                                       template->gpio, template->name);
+                       return 0;
+               }
 
-       /* skip leds that aren't available */
-       if (!gpio_is_valid(template->gpio)) {
-               dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
-                               template->gpio, template->name);
-               return 0;
-       }
+               if (template->active_low)
+                       flags |= GPIOF_ACTIVE_LOW;
 
-       ret = devm_gpio_request(parent, template->gpio, template->name);
-       if (ret < 0)
-               return ret;
+               ret = devm_gpio_request_one(parent, template->gpio, flags,
+                                           template->name);
+               if (ret < 0)
+                       return ret;
+
+               led_dat->gpiod = gpio_to_desc(template->gpio);
+               if (IS_ERR(led_dat->gpiod))
+                       return PTR_ERR(led_dat->gpiod);
+       }
 
        led_dat->cdev.name = template->name;
        led_dat->cdev.default_trigger = template->default_trigger;
-       led_dat->gpio = template->gpio;
-       led_dat->can_sleep = gpio_cansleep(template->gpio);
-       led_dat->active_low = template->active_low;
+       led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
        led_dat->blinking = 0;
        if (blink_set) {
                led_dat->platform_gpio_blink_set = blink_set;
@@ -122,30 +131,24 @@ static int create_gpio_led(const struct gpio_led *template,
        }
        led_dat->cdev.brightness_set = gpio_led_set;
        if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
-               state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
+               state = !!gpiod_get_value_cansleep(led_dat->gpiod);
        else
                state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
        led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
        if (!template->retain_state_suspended)
                led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 
-       ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+       ret = gpiod_direction_output(led_dat->gpiod, state);
        if (ret < 0)
                return ret;
 
        INIT_WORK(&led_dat->work, gpio_led_work);
 
-       ret = led_classdev_register(parent, &led_dat->cdev);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return led_classdev_register(parent, &led_dat->cdev);
 }
 
 static void delete_gpio_led(struct gpio_led_data *led)
 {
-       if (!gpio_is_valid(led->gpio))
-               return;
        led_classdev_unregister(&led->cdev);
        cancel_work_sync(&led->work);
 }
@@ -161,40 +164,47 @@ static inline int sizeof_gpio_leds_priv(int num_leds)
                (sizeof(struct gpio_led_data) * num_leds);
 }
 
-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node, *child;
+       struct device *dev = &pdev->dev;
+       struct fwnode_handle *child;
        struct gpio_leds_priv *priv;
        int count, ret;
+       struct device_node *np;
 
-       /* count LEDs in this device, so we know how much to allocate */
-       count = of_get_available_child_count(np);
+       count = device_get_child_node_count(dev);
        if (!count)
                return ERR_PTR(-ENODEV);
 
-       for_each_available_child_of_node(np, child)
-               if (of_get_gpio(child, 0) == -EPROBE_DEFER)
-                       return ERR_PTR(-EPROBE_DEFER);
-
-       priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
-                       GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
        if (!priv)
                return ERR_PTR(-ENOMEM);
 
-       for_each_available_child_of_node(np, child) {
+       device_for_each_child_node(dev, child) {
                struct gpio_led led = {};
-               enum of_gpio_flags flags;
-               const char *state;
-
-               led.gpio = of_get_gpio_flags(child, 0, &flags);
-               led.active_low = flags & OF_GPIO_ACTIVE_LOW;
-               led.name = of_get_property(child, "label", NULL) ? : child->name;
-               led.default_trigger =
-                       of_get_property(child, "linux,default-trigger", NULL);
-               state = of_get_property(child, "default-state", NULL);
-               if (state) {
+               const char *state = NULL;
+
+               led.gpiod = devm_get_gpiod_from_child(dev, child);
+               if (IS_ERR(led.gpiod)) {
+                       fwnode_handle_put(child);
+                       goto err;
+               }
+
+               np = of_node(child);
+
+               if (fwnode_property_present(child, "label")) {
+                       fwnode_property_read_string(child, "label", &led.name);
+               } else {
+                       if (IS_ENABLED(CONFIG_OF) && !led.name && np)
+                               led.name = np->name;
+                       if (!led.name)
+                               return ERR_PTR(-EINVAL);
+               }
+               fwnode_property_read_string(child, "linux,default-trigger",
+                                           &led.default_trigger);
+
+               if (!fwnode_property_read_string(child, "linux,default_state",
+                                                &state)) {
                        if (!strcmp(state, "keep"))
                                led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
                        else if (!strcmp(state, "on"))
@@ -203,13 +213,13 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
                                led.default_state = LEDS_GPIO_DEFSTATE_OFF;
                }
 
-               if (of_get_property(child, "retain-state-suspended", NULL))
+               if (fwnode_property_present(child, "retain-state-suspended"))
                        led.retain_state_suspended = 1;
 
                ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
-                                     &pdev->dev, NULL);
+                                     dev, NULL);
                if (ret < 0) {
-                       of_node_put(child);
+                       fwnode_handle_put(child);
                        goto err;
                }
        }
@@ -228,12 +238,6 @@ static const struct of_device_id of_gpio_leds_match[] = {
 };
 
 MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
-       return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
 
 static int gpio_led_probe(struct platform_device *pdev)
 {
@@ -261,7 +265,7 @@ static int gpio_led_probe(struct platform_device *pdev)
                        }
                }
        } else {
-               priv = gpio_leds_create_of(pdev);
+               priv = gpio_leds_create(pdev);
                if (IS_ERR(priv))
                        return PTR_ERR(priv);
        }
@@ -288,7 +292,7 @@ static struct platform_driver gpio_led_driver = {
        .driver         = {
                .name   = "leds-gpio",
                .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(of_gpio_leds_match),
+               .of_match_table = of_gpio_leds_match,
        },
 };
 
index 932ed9b..b10aaed 100644 (file)
@@ -2190,7 +2190,7 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
                ret = smiapp_set_compose(subdev, fh, sel);
                break;
        default:
-               BUG();
+               ret = -EINVAL;
        }
 
        mutex_unlock(&sensor->mutex);
index 331edda..3bd386c 100644 (file)
@@ -1078,7 +1078,7 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
        for (line = 0; line < lines; line++) {
                while (offset && offset >= sg_dma_len(sg)) {
                        offset -= sg_dma_len(sg);
-                       sg++;
+                       sg = sg_next(sg);
                }
 
                if (lpi && line > 0 && !(line % lpi))
@@ -1101,14 +1101,14 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
                        *(rp++) = cpu_to_le32(0); /* bits 63-32 */
                        todo -= (sg_dma_len(sg)-offset);
                        offset = 0;
-                       sg++;
+                       sg = sg_next(sg);
                        while (todo > sg_dma_len(sg)) {
                                *(rp++) = cpu_to_le32(RISC_WRITE|
                                                    sg_dma_len(sg));
                                *(rp++) = cpu_to_le32(sg_dma_address(sg));
                                *(rp++) = cpu_to_le32(0); /* bits 63-32 */
                                todo -= sg_dma_len(sg);
-                               sg++;
+                               sg = sg_next(sg);
                        }
                        *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
                        *(rp++) = cpu_to_le32(sg_dma_address(sg));
index 172583d..8cbe6b4 100644 (file)
@@ -105,11 +105,8 @@ static irqreturn_t solo_isr(int irq, void *data)
        if (!status)
                return IRQ_NONE;
 
-       if (status & ~solo_dev->irq_mask) {
-               solo_reg_write(solo_dev, SOLO_IRQ_STAT,
-                              status & ~solo_dev->irq_mask);
-               status &= solo_dev->irq_mask;
-       }
+       /* Acknowledge all interrupts immediately */
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
 
        if (status & SOLO_IRQ_PCI_ERR)
                solo_p2m_error_isr(solo_dev);
@@ -132,9 +129,6 @@ static irqreturn_t solo_isr(int irq, void *data)
        if (status & SOLO_IRQ_G723)
                solo_g723_isr(solo_dev);
 
-       /* Clear all interrupts handled */
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
-
        return IRQ_HANDLED;
 }
 
index f1f098e..d16bc67 100644 (file)
@@ -259,8 +259,8 @@ again:
                        case 32:
                                if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
                                        protocol = RC_TYPE_RC6_MCE;
-                                       scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
                                        toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
+                                       scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
                                } else {
                                        protocol = RC_BIT_RC6_6A_32;
                                        toggle = 0;
index ccc0009..1c0dbf4 100644 (file)
@@ -632,7 +632,7 @@ static void s2255_fillbuff(struct s2255_vc *vc,
                        break;
                case V4L2_PIX_FMT_JPEG:
                case V4L2_PIX_FMT_MJPEG:
-                       buf->vb.v4l2_buf.length = jpgsize;
+                       vb2_set_plane_payload(&buf->vb, 0, jpgsize);
                        memcpy(vbuf, tmpbuf, jpgsize);
                        break;
                case V4L2_PIX_FMT_YUV422P:
index 1456ea7..9af299b 100644 (file)
@@ -74,7 +74,8 @@ config MFD_AXP20X
        select REGMAP_IRQ
        depends on I2C=y
        help
-         If you say Y here you get support for the X-Powers AXP202 and AXP209.
+         If you say Y here you get support for the X-Powers AXP202, AXP209 and
+         AXP288 power management IC (PMIC).
          This driver include only the core APIs. You have to select individual
          components like regulators or the PEK (Power Enable Key) under the
          corresponding menus.
index 6231adb..1df18d1 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
+ * axp20x.c - MFD core driver for the X-Powers' Power Management ICs
  *
- * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
- * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
- * as well as configurable GPIOs.
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
  *
  * Author: Carlo Caione <carlo@caione.org>
  *
 #include <linux/mfd/core.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/acpi.h>
 
 #define AXP20X_OFF     0x80
 
+static const char const *axp20x_model_names[] = {
+       "AXP202",
+       "AXP209",
+       "AXP288",
+};
+
 static const struct regmap_range axp20x_writeable_ranges[] = {
        regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
        regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
@@ -47,6 +54,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
        .n_yes_ranges   = ARRAY_SIZE(axp20x_volatile_ranges),
 };
 
+static const struct regmap_range axp288_writeable_ranges[] = {
+       regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
+       regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
+};
+
+static const struct regmap_range axp288_volatile_ranges[] = {
+       regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
+};
+
+static const struct regmap_access_table axp288_writeable_table = {
+       .yes_ranges     = axp288_writeable_ranges,
+       .n_yes_ranges   = ARRAY_SIZE(axp288_writeable_ranges),
+};
+
+static const struct regmap_access_table axp288_volatile_table = {
+       .yes_ranges     = axp288_volatile_ranges,
+       .n_yes_ranges   = ARRAY_SIZE(axp288_volatile_ranges),
+};
+
 static struct resource axp20x_pek_resources[] = {
        {
                .name   = "PEK_DBR",
@@ -61,6 +87,39 @@ static struct resource axp20x_pek_resources[] = {
        },
 };
 
+static struct resource axp288_battery_resources[] = {
+       {
+               .start = AXP288_IRQ_QWBTU,
+               .end   = AXP288_IRQ_QWBTU,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_WBTU,
+               .end   = AXP288_IRQ_WBTU,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_QWBTO,
+               .end   = AXP288_IRQ_QWBTO,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_WBTO,
+               .end   = AXP288_IRQ_WBTO,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_WL2,
+               .end   = AXP288_IRQ_WL2,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_WL1,
+               .end   = AXP288_IRQ_WL1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
 static const struct regmap_config axp20x_regmap_config = {
        .reg_bits       = 8,
        .val_bits       = 8,
@@ -70,47 +129,96 @@ static const struct regmap_config axp20x_regmap_config = {
        .cache_type     = REGCACHE_RBTREE,
 };
 
-#define AXP20X_IRQ(_irq, _off, _mask) \
-       [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+static const struct regmap_config axp288_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .wr_table       = &axp288_writeable_table,
+       .volatile_table = &axp288_volatile_table,
+       .max_register   = AXP288_FG_TUNE5,
+       .cache_type     = REGCACHE_RBTREE,
+};
+
+#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask)                   \
+       [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
 
 static const struct regmap_irq axp20x_regmap_irqs[] = {
-       AXP20X_IRQ(ACIN_OVER_V,         0, 7),
-       AXP20X_IRQ(ACIN_PLUGIN,         0, 6),
-       AXP20X_IRQ(ACIN_REMOVAL,        0, 5),
-       AXP20X_IRQ(VBUS_OVER_V,         0, 4),
-       AXP20X_IRQ(VBUS_PLUGIN,         0, 3),
-       AXP20X_IRQ(VBUS_REMOVAL,        0, 2),
-       AXP20X_IRQ(VBUS_V_LOW,          0, 1),
-       AXP20X_IRQ(BATT_PLUGIN,         1, 7),
-       AXP20X_IRQ(BATT_REMOVAL,        1, 6),
-       AXP20X_IRQ(BATT_ENT_ACT_MODE,   1, 5),
-       AXP20X_IRQ(BATT_EXIT_ACT_MODE,  1, 4),
-       AXP20X_IRQ(CHARG,               1, 3),
-       AXP20X_IRQ(CHARG_DONE,          1, 2),
-       AXP20X_IRQ(BATT_TEMP_HIGH,      1, 1),
-       AXP20X_IRQ(BATT_TEMP_LOW,       1, 0),
-       AXP20X_IRQ(DIE_TEMP_HIGH,       2, 7),
-       AXP20X_IRQ(CHARG_I_LOW,         2, 6),
-       AXP20X_IRQ(DCDC1_V_LONG,        2, 5),
-       AXP20X_IRQ(DCDC2_V_LONG,        2, 4),
-       AXP20X_IRQ(DCDC3_V_LONG,        2, 3),
-       AXP20X_IRQ(PEK_SHORT,           2, 1),
-       AXP20X_IRQ(PEK_LONG,            2, 0),
-       AXP20X_IRQ(N_OE_PWR_ON,         3, 7),
-       AXP20X_IRQ(N_OE_PWR_OFF,        3, 6),
-       AXP20X_IRQ(VBUS_VALID,          3, 5),
-       AXP20X_IRQ(VBUS_NOT_VALID,      3, 4),
-       AXP20X_IRQ(VBUS_SESS_VALID,     3, 3),
-       AXP20X_IRQ(VBUS_SESS_END,       3, 2),
-       AXP20X_IRQ(LOW_PWR_LVL1,        3, 1),
-       AXP20X_IRQ(LOW_PWR_LVL2,        3, 0),
-       AXP20X_IRQ(TIMER,               4, 7),
-       AXP20X_IRQ(PEK_RIS_EDGE,        4, 6),
-       AXP20X_IRQ(PEK_FAL_EDGE,        4, 5),
-       AXP20X_IRQ(GPIO3_INPUT,         4, 3),
-       AXP20X_IRQ(GPIO2_INPUT,         4, 2),
-       AXP20X_IRQ(GPIO1_INPUT,         4, 1),
-       AXP20X_IRQ(GPIO0_INPUT,         4, 0),
+       INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V,            0, 7),
+       INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN,            0, 6),
+       INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL,           0, 5),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V,            0, 4),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN,            0, 3),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL,           0, 2),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW,             0, 1),
+       INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN,            1, 7),
+       INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL,           1, 6),
+       INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE,      1, 5),
+       INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE,     1, 4),
+       INIT_REGMAP_IRQ(AXP20X, CHARG,                  1, 3),
+       INIT_REGMAP_IRQ(AXP20X, CHARG_DONE,             1, 2),
+       INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH,         1, 1),
+       INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW,          1, 0),
+       INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH,          2, 7),
+       INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW,            2, 6),
+       INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG,           2, 5),
+       INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG,           2, 4),
+       INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG,           2, 3),
+       INIT_REGMAP_IRQ(AXP20X, PEK_SHORT,              2, 1),
+       INIT_REGMAP_IRQ(AXP20X, PEK_LONG,               2, 0),
+       INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON,            3, 7),
+       INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF,           3, 6),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_VALID,             3, 5),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID,         3, 4),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID,        3, 3),
+       INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END,          3, 2),
+       INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1,           3, 1),
+       INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2,           3, 0),
+       INIT_REGMAP_IRQ(AXP20X, TIMER,                  4, 7),
+       INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE,           4, 6),
+       INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE,           4, 5),
+       INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT,            4, 3),
+       INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT,            4, 2),
+       INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT,            4, 1),
+       INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT,            4, 0),
+};
+
+/* some IRQs are compatible with axp20x models */
+static const struct regmap_irq axp288_regmap_irqs[] = {
+       INIT_REGMAP_IRQ(AXP288, VBUS_FALL,              0, 2),
+       INIT_REGMAP_IRQ(AXP288, VBUS_RISE,              0, 3),
+       INIT_REGMAP_IRQ(AXP288, OV,                     0, 4),
+
+       INIT_REGMAP_IRQ(AXP288, DONE,                   1, 2),
+       INIT_REGMAP_IRQ(AXP288, CHARGING,               1, 3),
+       INIT_REGMAP_IRQ(AXP288, SAFE_QUIT,              1, 4),
+       INIT_REGMAP_IRQ(AXP288, SAFE_ENTER,             1, 5),
+       INIT_REGMAP_IRQ(AXP288, ABSENT,                 1, 6),
+       INIT_REGMAP_IRQ(AXP288, APPEND,                 1, 7),
+
+       INIT_REGMAP_IRQ(AXP288, QWBTU,                  2, 0),
+       INIT_REGMAP_IRQ(AXP288, WBTU,                   2, 1),
+       INIT_REGMAP_IRQ(AXP288, QWBTO,                  2, 2),
+       INIT_REGMAP_IRQ(AXP288, WBTO,                   2, 3),
+       INIT_REGMAP_IRQ(AXP288, QCBTU,                  2, 4),
+       INIT_REGMAP_IRQ(AXP288, CBTU,                   2, 5),
+       INIT_REGMAP_IRQ(AXP288, QCBTO,                  2, 6),
+       INIT_REGMAP_IRQ(AXP288, CBTO,                   2, 7),
+
+       INIT_REGMAP_IRQ(AXP288, WL2,                    3, 0),
+       INIT_REGMAP_IRQ(AXP288, WL1,                    3, 1),
+       INIT_REGMAP_IRQ(AXP288, GPADC,                  3, 2),
+       INIT_REGMAP_IRQ(AXP288, OT,                     3, 7),
+
+       INIT_REGMAP_IRQ(AXP288, GPIO0,                  4, 0),
+       INIT_REGMAP_IRQ(AXP288, GPIO1,                  4, 1),
+       INIT_REGMAP_IRQ(AXP288, POKO,                   4, 2),
+       INIT_REGMAP_IRQ(AXP288, POKL,                   4, 3),
+       INIT_REGMAP_IRQ(AXP288, POKS,                   4, 4),
+       INIT_REGMAP_IRQ(AXP288, POKN,                   4, 5),
+       INIT_REGMAP_IRQ(AXP288, POKP,                   4, 6),
+       INIT_REGMAP_IRQ(AXP288, TIMER,                  4, 7),
+
+       INIT_REGMAP_IRQ(AXP288, MV_CHNG,                5, 0),
+       INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG,            5, 1),
 };
 
 static const struct of_device_id axp20x_of_match[] = {
@@ -128,16 +236,39 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
 
+static struct acpi_device_id axp20x_acpi_match[] = {
+       {
+               .id = "INT33F4",
+               .driver_data = AXP288_ID,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
+
 static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
        .name                   = "axp20x_irq_chip",
        .status_base            = AXP20X_IRQ1_STATE,
        .ack_base               = AXP20X_IRQ1_STATE,
        .mask_base              = AXP20X_IRQ1_EN,
-       .num_regs               = 5,
+       .mask_invert            = true,
+       .init_ack_masked        = true,
        .irqs                   = axp20x_regmap_irqs,
        .num_irqs               = ARRAY_SIZE(axp20x_regmap_irqs),
+       .num_regs               = 5,
+
+};
+
+static const struct regmap_irq_chip axp288_regmap_irq_chip = {
+       .name                   = "axp288_irq_chip",
+       .status_base            = AXP20X_IRQ1_STATE,
+       .ack_base               = AXP20X_IRQ1_STATE,
+       .mask_base              = AXP20X_IRQ1_EN,
        .mask_invert            = true,
        .init_ack_masked        = true,
+       .irqs                   = axp288_regmap_irqs,
+       .num_irqs               = ARRAY_SIZE(axp288_regmap_irqs),
+       .num_regs               = 6,
+
 };
 
 static struct mfd_cell axp20x_cells[] = {
@@ -150,36 +281,158 @@ static struct mfd_cell axp20x_cells[] = {
        },
 };
 
+static struct resource axp288_adc_resources[] = {
+       {
+               .name  = "GPADC",
+               .start = AXP288_IRQ_GPADC,
+               .end   = AXP288_IRQ_GPADC,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource axp288_charger_resources[] = {
+       {
+               .start = AXP288_IRQ_OV,
+               .end   = AXP288_IRQ_OV,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_DONE,
+               .end   = AXP288_IRQ_DONE,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_CHARGING,
+               .end   = AXP288_IRQ_CHARGING,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_SAFE_QUIT,
+               .end   = AXP288_IRQ_SAFE_QUIT,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_SAFE_ENTER,
+               .end   = AXP288_IRQ_SAFE_ENTER,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_QCBTU,
+               .end   = AXP288_IRQ_QCBTU,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_CBTU,
+               .end   = AXP288_IRQ_CBTU,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_QCBTO,
+               .end   = AXP288_IRQ_QCBTO,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = AXP288_IRQ_CBTO,
+               .end   = AXP288_IRQ_CBTO,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct mfd_cell axp288_cells[] = {
+       {
+               .name = "axp288_adc",
+               .num_resources = ARRAY_SIZE(axp288_adc_resources),
+               .resources = axp288_adc_resources,
+       },
+       {
+               .name = "axp288_charger",
+               .num_resources = ARRAY_SIZE(axp288_charger_resources),
+               .resources = axp288_charger_resources,
+       },
+       {
+               .name = "axp288_battery",
+               .num_resources = ARRAY_SIZE(axp288_battery_resources),
+               .resources = axp288_battery_resources,
+       },
+       {
+               .name = "axp288_pmic_acpi",
+       },
+};
+
 static struct axp20x_dev *axp20x_pm_power_off;
 static void axp20x_power_off(void)
 {
+       if (axp20x_pm_power_off->variant == AXP288_ID)
+               return;
+
        regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
                     AXP20X_OFF);
 }
 
+static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
+{
+       const struct acpi_device_id *acpi_id;
+       const struct of_device_id *of_id;
+
+       if (dev->of_node) {
+               of_id = of_match_device(axp20x_of_match, dev);
+               if (!of_id) {
+                       dev_err(dev, "Unable to match OF ID\n");
+                       return -ENODEV;
+               }
+               axp20x->variant = (long) of_id->data;
+       } else {
+               acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+               if (!acpi_id || !acpi_id->driver_data) {
+                       dev_err(dev, "Unable to match ACPI ID and data\n");
+                       return -ENODEV;
+               }
+               axp20x->variant = (long) acpi_id->driver_data;
+       }
+
+       switch (axp20x->variant) {
+       case AXP202_ID:
+       case AXP209_ID:
+               axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
+               axp20x->cells = axp20x_cells;
+               axp20x->regmap_cfg = &axp20x_regmap_config;
+               axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
+               break;
+       case AXP288_ID:
+               axp20x->cells = axp288_cells;
+               axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
+               axp20x->regmap_cfg = &axp288_regmap_config;
+               axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
+               break;
+       default:
+               dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
+               return -EINVAL;
+       }
+       dev_info(dev, "AXP20x variant %s found\n",
+               axp20x_model_names[axp20x->variant]);
+
+       return 0;
+}
+
 static int axp20x_i2c_probe(struct i2c_client *i2c,
                         const struct i2c_device_id *id)
 {
        struct axp20x_dev *axp20x;
-       const struct of_device_id *of_id;
        int ret;
 
        axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
        if (!axp20x)
                return -ENOMEM;
 
-       of_id = of_match_device(axp20x_of_match, &i2c->dev);
-       if (!of_id) {
-               dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
-               return -ENODEV;
-       }
-       axp20x->variant = (long) of_id->data;
+       ret = axp20x_match_device(axp20x, &i2c->dev);
+       if (ret)
+               return ret;
 
        axp20x->i2c_client = i2c;
        axp20x->dev = &i2c->dev;
        dev_set_drvdata(axp20x->dev, axp20x);
 
-       axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
+       axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
        if (IS_ERR(axp20x->regmap)) {
                ret = PTR_ERR(axp20x->regmap);
                dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
@@ -188,15 +441,15 @@ static int axp20x_i2c_probe(struct i2c_client *i2c,
 
        ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
                                  IRQF_ONESHOT | IRQF_SHARED, -1,
-                                 &axp20x_regmap_irq_chip,
+                                 axp20x->regmap_irq_chip,
                                  &axp20x->regmap_irqc);
        if (ret) {
                dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
                return ret;
        }
 
-       ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
-                             ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
+       ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
+                       axp20x->nr_cells, NULL, 0, NULL);
 
        if (ret) {
                dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
@@ -234,6 +487,7 @@ static struct i2c_driver axp20x_i2c_driver = {
                .name   = "axp20x",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(axp20x_of_match),
+               .acpi_match_table = ACPI_PTR(axp20x_acpi_match),
        },
        .probe          = axp20x_i2c_probe,
        .remove         = axp20x_i2c_remove,
index 7107cab..c85e2ec 100644 (file)
@@ -106,6 +106,9 @@ static struct mfd_cell crystal_cove_dev[] = {
                .num_resources = ARRAY_SIZE(gpio_resources),
                .resources = gpio_resources,
        },
+       {
+               .name = "crystal_cove_pmic",
+       },
 };
 
 static struct regmap_config crystal_cove_regmap_config = {
index 634f729..0a1af93 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <linux/spi/spi.h>
 #include <linux/spi/eeprom.h>
-#include <linux/of.h>
+#include <linux/property.h>
 
 /*
  * NOTE: this is an *EEPROM* driver.  The vagaries of product naming
@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
 
 /*-------------------------------------------------------------------------*/
 
-static int at25_np_to_chip(struct device *dev,
-                          struct device_node *np,
-                          struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
 {
        u32 val;
 
        memset(chip, 0, sizeof(*chip));
-       strncpy(chip->name, np->name, sizeof(chip->name));
+       strncpy(chip->name, "at25", sizeof(chip->name));
 
-       if (of_property_read_u32(np, "size", &val) == 0 ||
-           of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+       if (device_property_read_u32(dev, "size", &val) == 0 ||
+           device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
                chip->byte_len = val;
        } else {
                dev_err(dev, "Error: missing \"size\" property\n");
                return -ENODEV;
        }
 
-       if (of_property_read_u32(np, "pagesize", &val) == 0 ||
-           of_property_read_u32(np, "at25,page-size", &val) == 0) {
+       if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
+           device_property_read_u32(dev, "at25,page-size", &val) == 0) {
                chip->page_size = (u16)val;
        } else {
                dev_err(dev, "Error: missing \"pagesize\" property\n");
                return -ENODEV;
        }
 
-       if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+       if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
                chip->flags = (u16)val;
        } else {
-               if (of_property_read_u32(np, "address-width", &val)) {
+               if (device_property_read_u32(dev, "address-width", &val)) {
                        dev_err(dev,
                                "Error: missing \"address-width\" property\n");
                        return -ENODEV;
@@ -350,7 +348,7 @@ static int at25_np_to_chip(struct device *dev,
                                val);
                        return -ENODEV;
                }
-               if (of_find_property(np, "read-only", NULL))
+               if (device_property_present(dev, "read-only"))
                        chip->flags |= EE_READONLY;
        }
        return 0;
@@ -360,21 +358,15 @@ static int at25_probe(struct spi_device *spi)
 {
        struct at25_data        *at25 = NULL;
        struct spi_eeprom       chip;
-       struct device_node      *np = spi->dev.of_node;
        int                     err;
        int                     sr;
        int                     addrlen;
 
        /* Chip description */
        if (!spi->dev.platform_data) {
-               if (np) {
-                       err = at25_np_to_chip(&spi->dev, np, &chip);
-                       if (err)
-                               return err;
-               } else {
-                       dev_err(&spi->dev, "Error: no chip description\n");
-                       return -ENODEV;
-               }
+               err = at25_fw_to_chip(&spi->dev, &chip);
+               if (err)
+                       return err;
        } else
                chip = *(struct spi_eeprom *)spi->dev.platform_data;
 
index c13d83e..45f09a6 100644 (file)
@@ -225,7 +225,12 @@ static int bond_changelink(struct net_device *bond_dev,
 
                bond_option_arp_ip_targets_clear(bond);
                nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
-                       __be32 target = nla_get_be32(attr);
+                       __be32 target;
+
+                       if (nla_len(attr) < sizeof(target))
+                               return -EINVAL;
+
+                       target = nla_get_be32(attr);
 
                        bond_opt_initval(&newval, (__force u64)target);
                        err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
index 8520d55..279873c 100644 (file)
@@ -2442,9 +2442,13 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
                     SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full |
                     SUPPORTED_10000baseKX4_Full;
        else if (type == FW_PORT_TYPE_FIBER_XFI ||
-                type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
+                type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) {
                v |= SUPPORTED_FIBRE;
-       else if (type == FW_PORT_TYPE_BP40_BA)
+               if (caps & FW_PORT_CAP_SPEED_1G)
+                       v |= SUPPORTED_1000baseT_Full;
+               if (caps & FW_PORT_CAP_SPEED_10G)
+                       v |= SUPPORTED_10000baseT_Full;
+       } else if (type == FW_PORT_TYPE_BP40_BA)
                v |= SUPPORTED_40000baseSR4_Full;
 
        if (caps & FW_PORT_CAP_ANEG)
index 60e9c2c..b5db6b3 100644 (file)
@@ -917,21 +917,13 @@ static int sh_eth_reset(struct net_device *ndev)
        return ret;
 }
 
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
 static void sh_eth_set_receive_align(struct sk_buff *skb)
 {
-       int reserve;
+       uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1);
 
-       reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1));
        if (reserve)
-               skb_reserve(skb, reserve);
+               skb_reserve(skb, SH_ETH_RX_ALIGN - reserve);
 }
-#else
-static void sh_eth_set_receive_align(struct sk_buff *skb)
-{
-       skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN);
-}
-#endif
 
 
 /* CPU <-> EDMAC endian convert */
@@ -1119,6 +1111,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
        struct sh_eth_txdesc *txdesc = NULL;
        int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring;
        int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
+       int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1;
 
        mdp->cur_rx = 0;
        mdp->cur_tx = 0;
@@ -1131,21 +1124,21 @@ static void sh_eth_ring_format(struct net_device *ndev)
        for (i = 0; i < mdp->num_rx_ring; i++) {
                /* skb */
                mdp->rx_skbuff[i] = NULL;
-               skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz);
+               skb = netdev_alloc_skb(ndev, skbuff_size);
                mdp->rx_skbuff[i] = skb;
                if (skb == NULL)
                        break;
-               dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz,
-                              DMA_FROM_DEVICE);
                sh_eth_set_receive_align(skb);
 
                /* RX descriptor */
                rxdesc = &mdp->rx_ring[i];
+               /* The size of the buffer is a multiple of 16 bytes. */
+               rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
+               dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length,
+                              DMA_FROM_DEVICE);
                rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
                rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
-               /* The size of the buffer is 16 byte boundary. */
-               rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
                /* Rx descriptor address set */
                if (i == 0) {
                        sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR);
@@ -1397,6 +1390,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        struct sk_buff *skb;
        u16 pkt_len = 0;
        u32 desc_status;
+       int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1;
 
        rxdesc = &mdp->rx_ring[entry];
        while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
@@ -1448,7 +1442,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                        if (mdp->cd->rpadir)
                                skb_reserve(skb, NET_IP_ALIGN);
                        dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr,
-                                               mdp->rx_buf_sz,
+                                               ALIGN(mdp->rx_buf_sz, 16),
                                                DMA_FROM_DEVICE);
                        skb_put(skb, pkt_len);
                        skb->protocol = eth_type_trans(skb, ndev);
@@ -1468,13 +1462,13 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
 
                if (mdp->rx_skbuff[entry] == NULL) {
-                       skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz);
+                       skb = netdev_alloc_skb(ndev, skbuff_size);
                        mdp->rx_skbuff[entry] = skb;
                        if (skb == NULL)
                                break;  /* Better luck next round. */
-                       dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz,
-                                      DMA_FROM_DEVICE);
                        sh_eth_set_receive_align(skb);
+                       dma_map_single(&ndev->dev, skb->data,
+                                      rxdesc->buffer_length, DMA_FROM_DEVICE);
 
                        skb_checksum_none_assert(skb);
                        rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
@@ -2042,6 +2036,8 @@ static int sh_eth_open(struct net_device *ndev)
        if (ret)
                goto out_free_irq;
 
+       mdp->is_opened = 1;
+
        return ret;
 
 out_free_irq:
@@ -2131,6 +2127,36 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        return NETDEV_TX_OK;
 }
 
+static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+
+       if (sh_eth_is_rz_fast_ether(mdp))
+               return &ndev->stats;
+
+       if (!mdp->is_opened)
+               return &ndev->stats;
+
+       ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR);
+       sh_eth_write(ndev, 0, TROCR);   /* (write clear) */
+       ndev->stats.collisions += sh_eth_read(ndev, CDCR);
+       sh_eth_write(ndev, 0, CDCR);    /* (write clear) */
+       ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR);
+       sh_eth_write(ndev, 0, LCCR);    /* (write clear) */
+
+       if (sh_eth_is_gether(mdp)) {
+               ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);
+               sh_eth_write(ndev, 0, CERCR);   /* (write clear) */
+               ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);
+               sh_eth_write(ndev, 0, CEECR);   /* (write clear) */
+       } else {
+               ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
+               sh_eth_write(ndev, 0, CNDCR);   /* (write clear) */
+       }
+
+       return &ndev->stats;
+}
+
 /* device close function */
 static int sh_eth_close(struct net_device *ndev)
 {
@@ -2145,6 +2171,7 @@ static int sh_eth_close(struct net_device *ndev)
        sh_eth_write(ndev, 0, EDTRR);
        sh_eth_write(ndev, 0, EDRRR);
 
+       sh_eth_get_stats(ndev);
        /* PHY Disconnect */
        if (mdp->phydev) {
                phy_stop(mdp->phydev);
@@ -2163,36 +2190,9 @@ static int sh_eth_close(struct net_device *ndev)
 
        pm_runtime_put_sync(&mdp->pdev->dev);
 
-       return 0;
-}
-
-static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
-{
-       struct sh_eth_private *mdp = netdev_priv(ndev);
-
-       if (sh_eth_is_rz_fast_ether(mdp))
-               return &ndev->stats;
+       mdp->is_opened = 0;
 
-       pm_runtime_get_sync(&mdp->pdev->dev);
-
-       ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR);
-       sh_eth_write(ndev, 0, TROCR);   /* (write clear) */
-       ndev->stats.collisions += sh_eth_read(ndev, CDCR);
-       sh_eth_write(ndev, 0, CDCR);    /* (write clear) */
-       ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR);
-       sh_eth_write(ndev, 0, LCCR);    /* (write clear) */
-       if (sh_eth_is_gether(mdp)) {
-               ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR);
-               sh_eth_write(ndev, 0, CERCR);   /* (write clear) */
-               ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR);
-               sh_eth_write(ndev, 0, CEECR);   /* (write clear) */
-       } else {
-               ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR);
-               sh_eth_write(ndev, 0, CNDCR);   /* (write clear) */
-       }
-       pm_runtime_put_sync(&mdp->pdev->dev);
-
-       return &ndev->stats;
+       return 0;
 }
 
 /* ioctl to device function */
index b37c427..22301bf 100644 (file)
@@ -162,9 +162,9 @@ enum {
 
 /* Driver's parameters */
 #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
-#define SH4_SKB_RX_ALIGN       32
+#define SH_ETH_RX_ALIGN                32
 #else
-#define SH2_SH3_SKB_RX_ALIGN   2
+#define SH_ETH_RX_ALIGN                2
 #endif
 
 /* Register's bits
@@ -522,6 +522,7 @@ struct sh_eth_private {
 
        unsigned no_ether_link:1;
        unsigned ether_link_active_low:1;
+       unsigned is_opened:1;
 };
 
 static inline void sh_eth_soft_swap(char *src, int len)
index 5b0da39..58a1a0a 100644 (file)
@@ -265,6 +265,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
 
        plat_dat = dev_get_platdata(&pdev->dev);
 
+       if (!plat_dat)
+               plat_dat = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct plat_stmmacenet_data),
+                                       GFP_KERNEL);
+       if (!plat_dat) {
+               pr_err("%s: ERROR: no memory", __func__);
+               return  -ENOMEM;
+       }
+
        /* Set default value for multicast hash bins */
        plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
 
@@ -272,15 +281,6 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        plat_dat->unicast_filter_entries = 1;
 
        if (pdev->dev.of_node) {
-               if (!plat_dat)
-                       plat_dat = devm_kzalloc(&pdev->dev,
-                                       sizeof(struct plat_stmmacenet_data),
-                                       GFP_KERNEL);
-               if (!plat_dat) {
-                       pr_err("%s: ERROR: no memory", __func__);
-                       return  -ENOMEM;
-               }
-
                ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
                if (ret) {
                        pr_err("%s: main dt probe failed", __func__);
index cca8713..ece8d18 100644 (file)
@@ -496,9 +496,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue,
                len = skb_frag_size(frag);
                offset = frag->page_offset;
 
-               /* Data must not cross a page boundary. */
-               BUG_ON(len + offset > PAGE_SIZE<<compound_order(page));
-
                /* Skip unused frames from start of page */
                page += offset >> PAGE_SHIFT;
                offset &= ~PAGE_MASK;
@@ -506,8 +503,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue,
                while (len > 0) {
                        unsigned long bytes;
 
-                       BUG_ON(offset >= PAGE_SIZE);
-
                        bytes = PAGE_SIZE - offset;
                        if (bytes > len)
                                bytes = len;
index 3823edf..4c2ccde 100644 (file)
@@ -1249,6 +1249,39 @@ int of_property_read_u64(const struct device_node *np, const char *propname,
 }
 EXPORT_SYMBOL_GPL(of_property_read_u64);
 
+/**
+ * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * from a property.
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ * @out_values:        pointer to return value, modified only if return value is 0.
+ * @sz:                number of array elements to read
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_array(const struct device_node *np,
+                              const char *propname, u64 *out_values,
+                              size_t sz)
+{
+       const __be32 *val = of_find_property_value_of_size(np, propname,
+                                               (sz * sizeof(*out_values)));
+
+       if (IS_ERR(val))
+               return PTR_ERR(val);
+
+       while (sz--) {
+               *out_values++ = of_read_number(val, 2);
+               val += 2;
+       }
+       return 0;
+}
+
 /**
  * of_property_read_string - Find and read a string from a property
  * @np:                device node from which the property value is to be read.
index 30e97bc..d134710 100644 (file)
@@ -964,8 +964,6 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
                                        phys_addr_t size, bool nomap)
 {
-       if (memblock_is_region_reserved(base, size))
-               return -EBUSY;
        if (nomap)
                return memblock_remove(base, size);
        return memblock_reserve(base, size);
index 3d43874..19bb19c 100644 (file)
@@ -276,6 +276,7 @@ struct tegra_pcie {
 
        struct resource all;
        struct resource io;
+       struct resource pio;
        struct resource mem;
        struct resource prefetch;
        struct resource busn;
@@ -658,7 +659,6 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
 {
        struct tegra_pcie *pcie = sys_to_pcie(sys);
        int err;
-       phys_addr_t io_start;
 
        err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
        if (err < 0)
@@ -668,14 +668,12 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        if (err)
                return err;
 
-       io_start = pci_pio_to_address(pcie->io.start);
-
        pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
        pci_add_resource_offset(&sys->resources, &pcie->prefetch,
                                sys->mem_offset);
        pci_add_resource(&sys->resources, &pcie->busn);
 
-       pci_ioremap_io(nr * SZ_64K, io_start);
+       pci_ioremap_io(pcie->pio.start, pcie->io.start);
 
        return 1;
 }
@@ -786,7 +784,6 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
 static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
 {
        u32 fpci_bar, size, axi_address;
-       phys_addr_t io_start = pci_pio_to_address(pcie->io.start);
 
        /* Bar 0: type 1 extended configuration space */
        fpci_bar = 0xfe100000;
@@ -799,7 +796,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
        /* Bar 1: downstream IO bar */
        fpci_bar = 0xfdfc0000;
        size = resource_size(&pcie->io);
-       axi_address = io_start;
+       axi_address = pcie->io.start;
        afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
        afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
        afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
@@ -1690,8 +1687,23 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
 
                switch (res.flags & IORESOURCE_TYPE_BITS) {
                case IORESOURCE_IO:
-                       memcpy(&pcie->io, &res, sizeof(res));
-                       pcie->io.name = np->full_name;
+                       memcpy(&pcie->pio, &res, sizeof(res));
+                       pcie->pio.name = np->full_name;
+
+                       /*
+                        * The Tegra PCIe host bridge uses this to program the
+                        * mapping of the I/O space to the physical address,
+                        * so we override the .start and .end fields here that
+                        * of_pci_range_to_resource() converted to I/O space.
+                        * We also set the IORESOURCE_MEM type to clarify that
+                        * the resource is in the physical memory space.
+                        */
+                       pcie->io.start = range.cpu_addr;
+                       pcie->io.end = range.cpu_addr + range.size - 1;
+                       pcie->io.flags = IORESOURCE_MEM;
+                       pcie->io.name = "I/O";
+
+                       memcpy(&res, &pcie->io, sizeof(res));
                        break;
 
                case IORESOURCE_MEM:
index 8532c3e..1626dc6 100644 (file)
@@ -161,7 +161,7 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
 static const struct s3c2410_wdt_variant drv_data_exynos7 = {
        .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
        .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
-       .mask_bit = 0,
+       .mask_bit = 23,
        .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
        .rst_stat_bit = 23,     /* A57 WDTRESET */
        .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
index 6df8d3d..b8b92c2 100644 (file)
@@ -736,7 +736,12 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
        }
 
        alias = d_find_alias(inode);
-       if (alias && !vfat_d_anon_disconn(alias)) {
+       /*
+        * Checking "alias->d_parent == dentry->d_parent" to make sure
+        * FS is not corrupted (especially double linked dir).
+        */
+       if (alias && alias->d_parent == dentry->d_parent &&
+           !vfat_d_anon_disconn(alias)) {
                /*
                 * This inode has non anonymous-DCACHE_DISCONNECTED
                 * dentry. This means, the user did ->lookup() by an
@@ -755,12 +760,9 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
 
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
-       dentry->d_time = dentry->d_parent->d_inode->i_version;
-       dentry = d_splice_alias(inode, dentry);
-       if (dentry)
-               dentry->d_time = dentry->d_parent->d_inode->i_version;
-       return dentry;
-
+       if (!inode)
+               dentry->d_time = dir->i_version;
+       return d_splice_alias(inode, dentry);
 error:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
        return ERR_PTR(err);
@@ -793,7 +795,6 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
-       dentry->d_time = dentry->d_parent->d_inode->i_version;
        d_instantiate(dentry, inode);
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
@@ -824,6 +825,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
        clear_nlink(inode);
        inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
        fat_detach(inode);
+       dentry->d_time = dir->i_version;
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 
@@ -849,6 +851,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
        clear_nlink(inode);
        inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
        fat_detach(inode);
+       dentry->d_time = dir->i_version;
 out:
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
 
@@ -889,7 +892,6 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
        /* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
-       dentry->d_time = dentry->d_parent->d_inode->i_version;
        d_instantiate(dentry, inode);
 
        mutex_unlock(&MSDOS_SB(sb)->s_lock);
index e4dc747..1df94fa 100644 (file)
@@ -1853,13 +1853,12 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
                                journal->j_chksum_driver = NULL;
                                return 0;
                        }
-               }
 
-               /* Precompute checksum seed for all metadata */
-               if (jbd2_journal_has_csum_v2or3(journal))
+                       /* Precompute checksum seed for all metadata */
                        journal->j_csum_seed = jbd2_chksum(journal, ~0,
                                                           sb->s_uuid,
                                                           sizeof(sb->s_uuid));
+               }
        }
 
        /* If enabling v1 checksums, downgrade superblock */
index 88cb477..d5ec6c8 100644 (file)
@@ -111,7 +111,9 @@ struct acpi_gtm_info {
 struct acpi_pld_info {
        u8 revision;
        u8 ignore_color;
-       u32 color;
+       u8 red;
+       u8 green;
+       u8 blue;
        u16 width;
        u16 height;
        u8 user_visible;
@@ -155,8 +157,14 @@ struct acpi_pld_info {
 #define ACPI_PLD_GET_IGNORE_COLOR(dword)        ACPI_GET_BITS (dword, 7, ACPI_1BIT_MASK)
 #define ACPI_PLD_SET_IGNORE_COLOR(dword,value)  ACPI_SET_BITS (dword, 7, ACPI_1BIT_MASK, value)        /* Offset 7, Len 1 */
 
-#define ACPI_PLD_GET_COLOR(dword)               ACPI_GET_BITS (dword, 8, ACPI_24BIT_MASK)
-#define ACPI_PLD_SET_COLOR(dword,value)         ACPI_SET_BITS (dword, 8, ACPI_24BIT_MASK, value)       /* Offset 8, Len 24 */
+#define ACPI_PLD_GET_RED(dword)                 ACPI_GET_BITS (dword, 8, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_RED(dword,value)           ACPI_SET_BITS (dword, 8, ACPI_8BIT_MASK, value)        /* Offset 8, Len 8 */
+
+#define ACPI_PLD_GET_GREEN(dword)               ACPI_GET_BITS (dword, 16, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_GREEN(dword,value)         ACPI_SET_BITS (dword, 16, ACPI_8BIT_MASK, value)       /* Offset 16, Len 8 */
+
+#define ACPI_PLD_GET_BLUE(dword)                ACPI_GET_BITS (dword, 24, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_BLUE(dword,value)          ACPI_SET_BITS (dword, 24, ACPI_8BIT_MASK, value)       /* Offset 24, Len 8 */
 
 /* Second 32-bit dword, bits 33:63 */
 
index f34a083..d539084 100644 (file)
@@ -27,6 +27,7 @@
 #define __ACPI_BUS_H__
 
 #include <linux/device.h>
+#include <linux/property.h>
 
 /* TBD: Make dynamic */
 #define ACPI_MAX_HANDLES       10
@@ -337,10 +338,20 @@ struct acpi_device_physical_node {
        bool put_online:1;
 };
 
+/* ACPI Device Specific Data (_DSD) */
+struct acpi_device_data {
+       const union acpi_object *pointer;
+       const union acpi_object *properties;
+       const union acpi_object *of_compatible;
+};
+
+struct acpi_gpio_mapping;
+
 /* Device */
 struct acpi_device {
        int device_type;
        acpi_handle handle;             /* no handle for fixed hardware */
+       struct fwnode_handle fwnode;
        struct acpi_device *parent;
        struct list_head children;
        struct list_head node;
@@ -353,17 +364,35 @@ struct acpi_device {
        struct acpi_device_wakeup wakeup;
        struct acpi_device_perf performance;
        struct acpi_device_dir dir;
+       struct acpi_device_data data;
        struct acpi_scan_handler *handler;
        struct acpi_hotplug_context *hp;
        struct acpi_driver *driver;
+       const struct acpi_gpio_mapping *driver_gpios;
        void *driver_data;
        struct device dev;
        unsigned int physical_node_count;
+       unsigned int dep_unmet;
        struct list_head physical_node_list;
        struct mutex physical_node_lock;
        void (*remove)(struct acpi_device *);
 };
 
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+       return fwnode && fwnode->type == FWNODE_ACPI;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+       return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+       return &adev->fwnode;
+}
+
 static inline void *acpi_driver_data(struct acpi_device *d)
 {
        return d->driver_data;
index ab2acf6..5ba7846 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20140926
+#define ACPI_CA_VERSION                 0x20141107
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index 7000e66..bbef173 100644 (file)
@@ -736,6 +736,10 @@ typedef u32 acpi_event_status;
 #define ACPI_GPE_ENABLE                 0
 #define ACPI_GPE_DISABLE                1
 #define ACPI_GPE_CONDITIONAL_ENABLE     2
+#define ACPI_GPE_SAVE_MASK              4
+
+#define ACPI_GPE_ENABLE_SAVE            (ACPI_GPE_ENABLE | ACPI_GPE_SAVE_MASK)
+#define ACPI_GPE_DISABLE_SAVE           (ACPI_GPE_DISABLE | ACPI_GPE_SAVE_MASK)
 
 /*
  * GPE info flags - Per GPE
index 9b9b6f2..3ca9b75 100644 (file)
@@ -67,9 +67,6 @@ struct acpi_processor_cx {
 };
 
 struct acpi_processor_power {
-       struct acpi_processor_cx *state;
-       unsigned long bm_check_timestamp;
-       u32 default_state;
        int count;
        struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
        int timer_broadcast_on_state;
@@ -313,11 +310,13 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
 #endif                         /* CONFIG_CPU_FREQ */
 
 /* in processor_core.c */
-void acpi_processor_set_pdc(acpi_handle handle);
 int acpi_get_apicid(acpi_handle, int type, u32 acpi_id);
 int acpi_map_cpuid(int apic_id, u32 acpi_id);
 int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
 
+/* in processor_pdc.c */
+void acpi_processor_set_pdc(acpi_handle handle);
+
 /* in processor_throttling.c */
 int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
 int acpi_processor_get_throttling_info(struct acpi_processor *pr);
index 407a12f..d7a5fcf 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>      /* for struct resource */
 #include <linux/device.h>
+#include <linux/property.h>
 
 #ifndef _LINUX
 #define _LINUX
@@ -123,6 +124,10 @@ int acpi_numa_init (void);
 
 int acpi_table_init (void);
 int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
+int __init acpi_parse_entries(char *id, unsigned long table_size,
+                             acpi_tbl_entry_handler handler,
+                             struct acpi_table_header *table_header,
+                             int entry_id, unsigned int max_entries);
 int __init acpi_table_parse_entries(char *id, unsigned long table_size,
                                    int entry_id,
                                    acpi_tbl_entry_handler handler,
@@ -423,14 +428,11 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                                               const struct device *dev);
 
-static inline bool acpi_driver_match_device(struct device *dev,
-                                           const struct device_driver *drv)
-{
-       return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+                                    const struct device_driver *drv);
 int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
 int acpi_device_modalias(struct device *, char *, int);
+void acpi_walk_dep_device_list(acpi_handle handle);
 
 struct platform_device *acpi_create_platform_device(struct acpi_device *);
 #define ACPI_PTR(_ptr) (_ptr)
@@ -443,6 +445,23 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *);
 #define ACPI_COMPANION_SET(dev, adev)  do { } while (0)
 #define ACPI_HANDLE(dev)               (NULL)
 
+struct fwnode_handle;
+
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+       return false;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+       return NULL;
+}
+
 static inline const char *acpi_dev_name(struct acpi_device *adev)
 {
        return NULL;
@@ -659,4 +678,114 @@ do {                                                                      \
 #endif
 #endif
 
+struct acpi_gpio_params {
+       unsigned int crs_entry_index;
+       unsigned int line_index;
+       bool active_low;
+};
+
+struct acpi_gpio_mapping {
+       const char *name;
+       const struct acpi_gpio_params *data;
+       unsigned int size;
+};
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+                             const struct acpi_gpio_mapping *gpios);
+
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
+{
+       if (adev)
+               adev->driver_gpios = NULL;
+}
+#else
+static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+                             const struct acpi_gpio_mapping *gpios)
+{
+       return -ENXIO;
+}
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
+#endif
+
+/* Device properties */
+
+#define MAX_ACPI_REFERENCE_ARGS        8
+struct acpi_reference_args {
+       struct acpi_device *adev;
+       size_t nargs;
+       u64 args[MAX_ACPI_REFERENCE_ARGS];
+};
+
+#ifdef CONFIG_ACPI
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+                         acpi_object_type type, const union acpi_object **obj);
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+                               acpi_object_type type,
+                               const union acpi_object **obj);
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+                                   const char *name, size_t index,
+                                   struct acpi_reference_args *args);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+                     void **valptr);
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+                             enum dev_prop_type proptype, void *val);
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+                      enum dev_prop_type proptype, void *val, size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+                                       struct acpi_device *child);
+#else
+static inline int acpi_dev_get_property(struct acpi_device *adev,
+                                       const char *name, acpi_object_type type,
+                                       const union acpi_object **obj)
+{
+       return -ENXIO;
+}
+static inline int acpi_dev_get_property_array(struct acpi_device *adev,
+                                             const char *name,
+                                             acpi_object_type type,
+                                             const union acpi_object **obj)
+{
+       return -ENXIO;
+}
+static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+                               const char *name, const char *cells_name,
+                               size_t index, struct acpi_reference_args *args)
+{
+       return -ENXIO;
+}
+
+static inline int acpi_dev_prop_get(struct acpi_device *adev,
+                                   const char *propname,
+                                   void **valptr)
+{
+       return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read_single(struct acpi_device *adev,
+                                           const char *propname,
+                                           enum dev_prop_type proptype,
+                                           void *val)
+{
+       return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read(struct acpi_device *adev,
+                                    const char *propname,
+                                    enum dev_prop_type proptype,
+                                    void *val, size_t nval)
+{
+       return -ENXIO;
+}
+
+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+                                                     struct acpi_device *child)
+{
+       return NULL;
+}
+
+#endif
+
 #endif /*_LINUX_ACPI_H*/
index 12f146f..00b1b70 100644 (file)
@@ -94,6 +94,13 @@ int gpiod_to_irq(const struct gpio_desc *desc);
 struct gpio_desc *gpio_to_desc(unsigned gpio);
 int desc_to_gpio(const struct gpio_desc *desc);
 
+/* Child properties interface */
+struct fwnode_handle;
+
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+                                        const char *propname);
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+                                           struct fwnode_handle *child);
 #else /* CONFIG_GPIOLIB */
 
 static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
index 8b62246..ee2d8c6 100644 (file)
@@ -2,6 +2,7 @@
 #define _GPIO_KEYS_H
 
 struct device;
+struct gpio_desc;
 
 /**
  * struct gpio_keys_button - configuration parameters
@@ -17,6 +18,7 @@ struct device;
  *                     disable button via sysfs
  * @value:             axis value for %EV_ABS
  * @irq:               Irq number in case of interrupt keys
+ * @gpiod:             GPIO descriptor
  */
 struct gpio_keys_button {
        unsigned int code;
@@ -29,6 +31,7 @@ struct gpio_keys_button {
        bool can_disable;
        int value;
        unsigned int irq;
+       struct gpio_desc *gpiod;
 };
 
 /**
index a57611d..361101f 100644 (file)
@@ -261,6 +261,7 @@ struct gpio_led {
        unsigned        retain_state_suspended : 1;
        unsigned        default_state : 2;
        /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
+       struct gpio_desc *gpiod;
 };
 #define LEDS_GPIO_DEFSTATE_OFF         0
 #define LEDS_GPIO_DEFSTATE_ON          1
@@ -273,7 +274,7 @@ struct gpio_led_platform_data {
 #define GPIO_LED_NO_BLINK_LOW  0       /* No blink GPIO state low */
 #define GPIO_LED_NO_BLINK_HIGH 1       /* No blink GPIO state high */
 #define GPIO_LED_BLINK         2       /* Please, blink */
-       int             (*gpio_blink_set)(unsigned gpio, int state,
+       int             (*gpio_blink_set)(struct gpio_desc *desc, int state,
                                        unsigned long *delay_on,
                                        unsigned long *delay_off);
 };
index d0e31a2..81589d1 100644 (file)
@@ -14,6 +14,8 @@
 enum {
        AXP202_ID = 0,
        AXP209_ID,
+       AXP288_ID,
+       NR_AXP20X_VARIANTS,
 };
 
 #define AXP20X_DATACACHE(m)            (0x04 + (m))
@@ -49,11 +51,13 @@ enum {
 #define AXP20X_IRQ3_EN                 0x42
 #define AXP20X_IRQ4_EN                 0x43
 #define AXP20X_IRQ5_EN                 0x44
+#define AXP20X_IRQ6_EN                 0x45
 #define AXP20X_IRQ1_STATE              0x48
 #define AXP20X_IRQ2_STATE              0x49
 #define AXP20X_IRQ3_STATE              0x4a
 #define AXP20X_IRQ4_STATE              0x4b
 #define AXP20X_IRQ5_STATE              0x4c
+#define AXP20X_IRQ6_STATE              0x4d
 
 /* ADC */
 #define AXP20X_ACIN_V_ADC_H            0x56
@@ -116,6 +120,15 @@ enum {
 #define AXP20X_CC_CTRL                 0xb8
 #define AXP20X_FG_RES                  0xb9
 
+/* AXP288 specific registers */
+#define AXP288_PMIC_ADC_H               0x56
+#define AXP288_PMIC_ADC_L               0x57
+#define AXP288_ADC_TS_PIN_CTRL          0x84
+
+#define AXP288_PMIC_ADC_EN              0x84
+#define AXP288_FG_TUNE5                        0xed
+
+
 /* Regulators IDs */
 enum {
        AXP20X_LDO1 = 0,
@@ -169,12 +182,58 @@ enum {
        AXP20X_IRQ_GPIO0_INPUT,
 };
 
+enum axp288_irqs {
+       AXP288_IRQ_VBUS_FALL     = 2,
+       AXP288_IRQ_VBUS_RISE,
+       AXP288_IRQ_OV,
+       AXP288_IRQ_FALLING_ALT,
+       AXP288_IRQ_RISING_ALT,
+       AXP288_IRQ_OV_ALT,
+       AXP288_IRQ_DONE          = 10,
+       AXP288_IRQ_CHARGING,
+       AXP288_IRQ_SAFE_QUIT,
+       AXP288_IRQ_SAFE_ENTER,
+       AXP288_IRQ_ABSENT,
+       AXP288_IRQ_APPEND,
+       AXP288_IRQ_QWBTU,
+       AXP288_IRQ_WBTU,
+       AXP288_IRQ_QWBTO,
+       AXP288_IRQ_WBTO,
+       AXP288_IRQ_QCBTU,
+       AXP288_IRQ_CBTU,
+       AXP288_IRQ_QCBTO,
+       AXP288_IRQ_CBTO,
+       AXP288_IRQ_WL2,
+       AXP288_IRQ_WL1,
+       AXP288_IRQ_GPADC,
+       AXP288_IRQ_OT            = 31,
+       AXP288_IRQ_GPIO0,
+       AXP288_IRQ_GPIO1,
+       AXP288_IRQ_POKO,
+       AXP288_IRQ_POKL,
+       AXP288_IRQ_POKS,
+       AXP288_IRQ_POKN,
+       AXP288_IRQ_POKP,
+       AXP288_IRQ_TIMER,
+       AXP288_IRQ_MV_CHNG,
+       AXP288_IRQ_BC_USB_CHNG,
+};
+
+#define AXP288_TS_ADC_H                0x58
+#define AXP288_TS_ADC_L                0x59
+#define AXP288_GP_ADC_H                0x5a
+#define AXP288_GP_ADC_L                0x5b
+
 struct axp20x_dev {
        struct device                   *dev;
        struct i2c_client               *i2c_client;
        struct regmap                   *regmap;
        struct regmap_irq_chip_data     *regmap_irqc;
        long                            variant;
+       int                             nr_cells;
+       struct mfd_cell                 *cells;
+       const struct regmap_config      *regmap_cfg;
+       const struct regmap_irq_chip    *regmap_irq_chip;
 };
 
 #endif /* __LINUX_MFD_AXP20X_H */
index 29f0adc..cf79be1 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <linux/topology.h>
 #include <linux/notifier.h>
+#include <linux/property.h>
 
 #include <asm/byteorder.h>
 #include <asm/errno.h>
@@ -49,6 +50,7 @@ struct device_node {
        const char *type;
        phandle phandle;
        const char *full_name;
+       struct fwnode_handle fwnode;
 
        struct  property *properties;
        struct  property *deadprops;    /* removed properties */
@@ -79,6 +81,7 @@ extern struct kobj_type of_node_ktype;
 static inline void of_node_init(struct device_node *node)
 {
        kobject_init(&node->kobj, &of_node_ktype);
+       node->fwnode.type = FWNODE_OF;
 }
 
 /* true when node is initialized */
@@ -114,6 +117,16 @@ extern struct device_node *of_aliases;
 extern struct device_node *of_stdout;
 extern raw_spinlock_t devtree_lock;
 
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+       return fwnode && fwnode->type == FWNODE_OF;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+       return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
 static inline bool of_have_populated_dt(void)
 {
        return of_allnodes != NULL;
@@ -263,6 +276,10 @@ extern int of_property_read_u32_array(const struct device_node *np,
                                      size_t sz);
 extern int of_property_read_u64(const struct device_node *np,
                                const char *propname, u64 *out_value);
+extern int of_property_read_u64_array(const struct device_node *np,
+                                     const char *propname,
+                                     u64 *out_values,
+                                     size_t sz);
 
 extern int of_property_read_string(struct device_node *np,
                                   const char *propname,
@@ -355,6 +372,16 @@ bool of_console_check(struct device_node *dn, char *name, int index);
 
 #else /* CONFIG_OF */
 
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+       return false;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
 static inline const char* of_node_full_name(const struct device_node *np)
 {
        return "<no-node>";
@@ -477,6 +504,13 @@ static inline int of_property_read_u32_array(const struct device_node *np,
        return -ENOSYS;
 }
 
+static inline int of_property_read_u64_array(const struct device_node *np,
+                                            const char *propname,
+                                            u64 *out_values, size_t sz)
+{
+       return -ENOSYS;
+}
+
 static inline int of_property_read_string(struct device_node *np,
                                          const char *propname,
                                          const char **out_string)
diff --git a/include/linux/property.h b/include/linux/property.h
new file mode 100644 (file)
index 0000000..a6a3d98
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * property.h - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *          Mika Westerberg <mika.westerberg@linux.intel.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.
+ */
+
+#ifndef _LINUX_PROPERTY_H_
+#define _LINUX_PROPERTY_H_
+
+#include <linux/types.h>
+
+struct device;
+
+enum dev_prop_type {
+       DEV_PROP_U8,
+       DEV_PROP_U16,
+       DEV_PROP_U32,
+       DEV_PROP_U64,
+       DEV_PROP_STRING,
+       DEV_PROP_MAX,
+};
+
+bool device_property_present(struct device *dev, const char *propname);
+int device_property_read_u8_array(struct device *dev, const char *propname,
+                                 u8 *val, size_t nval);
+int device_property_read_u16_array(struct device *dev, const char *propname,
+                                  u16 *val, size_t nval);
+int device_property_read_u32_array(struct device *dev, const char *propname,
+                                  u32 *val, size_t nval);
+int device_property_read_u64_array(struct device *dev, const char *propname,
+                                  u64 *val, size_t nval);
+int device_property_read_string_array(struct device *dev, const char *propname,
+                                     const char **val, size_t nval);
+int device_property_read_string(struct device *dev, const char *propname,
+                               const char **val);
+
+enum fwnode_type {
+       FWNODE_INVALID = 0,
+       FWNODE_OF,
+       FWNODE_ACPI,
+};
+
+struct fwnode_handle {
+       enum fwnode_type type;
+};
+
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+                                 const char *propname, u8 *val,
+                                 size_t nval);
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+                                  const char *propname, u16 *val,
+                                  size_t nval);
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+                                  const char *propname, u32 *val,
+                                  size_t nval);
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+                                  const char *propname, u64 *val,
+                                  size_t nval);
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+                                     const char *propname, const char **val,
+                                     size_t nval);
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+                               const char *propname, const char **val);
+
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+                                                struct fwnode_handle *child);
+
+#define device_for_each_child_node(dev, child) \
+       for (child = device_get_next_child_node(dev, NULL); child; \
+            child = device_get_next_child_node(dev, child))
+
+void fwnode_handle_put(struct fwnode_handle *fwnode);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
+static inline bool device_property_read_bool(struct device *dev,
+                                            const char *propname)
+{
+       return device_property_present(dev, propname);
+}
+
+static inline int device_property_read_u8(struct device *dev,
+                                         const char *propname, u8 *val)
+{
+       return device_property_read_u8_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u16(struct device *dev,
+                                          const char *propname, u16 *val)
+{
+       return device_property_read_u16_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u32(struct device *dev,
+                                          const char *propname, u32 *val)
+{
+       return device_property_read_u32_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u64(struct device *dev,
+                                          const char *propname, u64 *val)
+{
+       return device_property_read_u64_array(dev, propname, val, 1);
+}
+
+static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode,
+                                            const char *propname)
+{
+       return fwnode_property_present(fwnode, propname);
+}
+
+static inline int fwnode_property_read_u8(struct fwnode_handle *fwnode,
+                                         const char *propname, u8 *val)
+{
+       return fwnode_property_read_u8_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u16(struct fwnode_handle *fwnode,
+                                          const char *propname, u16 *val)
+{
+       return fwnode_property_read_u16_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u32(struct fwnode_handle *fwnode,
+                                          const char *propname, u32 *val)
+{
+       return fwnode_property_read_u32_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
+                                          const char *propname, u64 *val)
+{
+       return fwnode_property_read_u64_array(fwnode, propname, val, 1);
+}
+
+#endif /* _LINUX_PROPERTY_H_ */
index 4c94f31..8523f9b 100644 (file)
@@ -427,7 +427,7 @@ header-y += virtio_net.h
 header-y += virtio_pci.h
 header-y += virtio_ring.h
 header-y += virtio_rng.h
-header=y += vm_sockets.h
+header-y += vm_sockets.h
 header-y += vt.h
 header-y += wait.h
 header-y += wanrouter.h
index 454f6c6..53c3310 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -507,13 +507,6 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
                return retval;
        }
 
-       id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
-       if (id < 0) {
-               ipc_rcu_putref(sma, sem_rcu_free);
-               return id;
-       }
-       ns->used_sems += nsems;
-
        sma->sem_base = (struct sem *) &sma[1];
 
        for (i = 0; i < nsems; i++) {
@@ -528,6 +521,14 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        INIT_LIST_HEAD(&sma->list_id);
        sma->sem_nsems = nsems;
        sma->sem_ctime = get_seconds();
+
+       id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+       if (id < 0) {
+               ipc_rcu_putref(sma, sem_rcu_free);
+               return id;
+       }
+       ns->used_sems += nsems;
+
        sem_unlock(sma, -1);
        rcu_read_unlock();
 
index 24beb9b..89e7283 100644 (file)
@@ -2874,10 +2874,14 @@ asmlinkage __visible void __sched schedule_user(void)
         * or we have been woken up remotely but the IPI has not yet arrived,
         * we haven't yet exited the RCU idle mode. Do it here manually until
         * we find a better solution.
+        *
+        * NB: There are buggy callers of this function.  Ideally we
+        * should warn if prev_state != IN_USER, but that will trigger
+        * too frequently to make sense yet.
         */
-       user_exit();
+       enum ctx_state prev_state = exception_enter();
        schedule();
-       user_enter();
+       exception_exit(prev_state);
 }
 #endif
 
index cce4dd6..2e65d20 100644 (file)
@@ -598,6 +598,7 @@ struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order,
 
        return pool;
 }
+EXPORT_SYMBOL(devm_gen_pool_create);
 
 /**
  * dev_get_gen_pool - Obtain the gen_pool (if any) for a device
index 0922579..5e25627 100644 (file)
@@ -28,7 +28,7 @@ void show_mem(unsigned int filter)
                                continue;
 
                        total += zone->present_pages;
-                       reserved = zone->present_pages - zone->managed_pages;
+                       reserved += zone->present_pages - zone->managed_pages;
 
                        if (is_highmem_idx(zoneid))
                                highmem += zone->present_pages;
index c30eec5..f2a3571 100644 (file)
@@ -244,8 +244,10 @@ int __frontswap_store(struct page *page)
                  the (older) page from frontswap
                 */
                inc_frontswap_failed_stores();
-               if (dup)
+               if (dup) {
                        __frontswap_clear(sis, offset);
+                       frontswap_ops->invalidate_page(type, offset);
+               }
        }
        if (frontswap_writethrough_enabled)
                /* report failure so swap also writes to swap device */
index 3e50383..d5f2ae9 100644 (file)
@@ -815,20 +815,20 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                if (!pte_file(pte)) {
                        swp_entry_t entry = pte_to_swp_entry(pte);
 
-                       if (swap_duplicate(entry) < 0)
-                               return entry.val;
-
-                       /* make sure dst_mm is on swapoff's mmlist. */
-                       if (unlikely(list_empty(&dst_mm->mmlist))) {
-                               spin_lock(&mmlist_lock);
-                               if (list_empty(&dst_mm->mmlist))
-                                       list_add(&dst_mm->mmlist,
-                                                &src_mm->mmlist);
-                               spin_unlock(&mmlist_lock);
-                       }
-                       if (likely(!non_swap_entry(entry)))
+                       if (likely(!non_swap_entry(entry))) {
+                               if (swap_duplicate(entry) < 0)
+                                       return entry.val;
+
+                               /* make sure dst_mm is on swapoff's mmlist. */
+                               if (unlikely(list_empty(&dst_mm->mmlist))) {
+                                       spin_lock(&mmlist_lock);
+                                       if (list_empty(&dst_mm->mmlist))
+                                               list_add(&dst_mm->mmlist,
+                                                        &src_mm->mmlist);
+                                       spin_unlock(&mmlist_lock);
+                               }
                                rss[MM_SWAPENTS]++;
-                       else if (is_migration_entry(entry)) {
+                       else if (is_migration_entry(entry)) {
                                page = migration_entry_to_page(entry);
 
                                if (PageAnon(page))
index 87e82b3..ae91989 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -776,8 +776,11 @@ again:                     remove_next = 1 + (end > next->vm_end);
                 * shrinking vma had, to cover any anon pages imported.
                 */
                if (exporter && exporter->anon_vma && !importer->anon_vma) {
-                       if (anon_vma_clone(importer, exporter))
-                               return -ENOMEM;
+                       int error;
+
+                       error = anon_vma_clone(importer, exporter);
+                       if (error)
+                               return error;
                        importer->anon_vma = exporter->anon_vma;
                }
        }
@@ -2469,7 +2472,8 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
        if (err)
                goto out_free_vma;
 
-       if (anon_vma_clone(new, vma))
+       err = anon_vma_clone(new, vma);
+       if (err)
                goto out_free_mpol;
 
        if (new->vm_file)
index 19886fb..3e4c721 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -274,6 +274,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
 {
        struct anon_vma_chain *avc;
        struct anon_vma *anon_vma;
+       int error;
 
        /* Don't bother if the parent process has no anon_vma here. */
        if (!pvma->anon_vma)
@@ -283,8 +284,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
         * First, attach the new VMA to the parent VMA's anon_vmas,
         * so rmap can find non-COWed pages in child processes.
         */
-       if (anon_vma_clone(vma, pvma))
-               return -ENOMEM;
+       error = anon_vma_clone(vma, pvma);
+       if (error)
+               return error;
 
        /* Then add our own anon_vma. */
        anon_vma = anon_vma_alloc();
index eb2b2ea..f34e053 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3076,7 +3076,7 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
        void *obj;
        int x;
 
-       VM_BUG_ON(nodeid > num_online_nodes());
+       VM_BUG_ON(nodeid < 0 || nodeid >= MAX_NUMNODES);
        n = get_node(cachep, nodeid);
        BUG_ON(!n);
 
index d4042e7..c5afd57 100644 (file)
@@ -165,6 +165,7 @@ static void vmpressure_work_fn(struct work_struct *work)
        unsigned long scanned;
        unsigned long reclaimed;
 
+       spin_lock(&vmpr->sr_lock);
        /*
         * Several contexts might be calling vmpressure(), so it is
         * possible that the work was rescheduled again before the old
@@ -173,11 +174,12 @@ static void vmpressure_work_fn(struct work_struct *work)
         * here. No need for any locks here since we don't care if
         * vmpr->reclaimed is in sync.
         */
-       if (!vmpr->scanned)
+       scanned = vmpr->scanned;
+       if (!scanned) {
+               spin_unlock(&vmpr->sr_lock);
                return;
+       }
 
-       spin_lock(&vmpr->sr_lock);
-       scanned = vmpr->scanned;
        reclaimed = vmpr->reclaimed;
        vmpr->scanned = 0;
        vmpr->reclaimed = 0;
index b9b7dfa..76321ea 100644 (file)
@@ -1498,6 +1498,7 @@ static int do_setlink(const struct sk_buff *skb,
                        goto errout;
                }
                if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
+                       put_net(net);
                        err = -EPERM;
                        goto errout;
                }
index 0f62326..2a47179 100644 (file)
@@ -63,6 +63,15 @@ static const struct rfkill_ops rfkill_gpio_ops = {
        .set_block = rfkill_gpio_set_power,
 };
 
+static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
+static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = {
+       { "reset-gpios", &reset_gpios, 1 },
+       { "shutdown-gpios", &shutdown_gpios, 1 },
+       { },
+};
+
 static int rfkill_gpio_acpi_probe(struct device *dev,
                                  struct rfkill_gpio_data *rfkill)
 {
@@ -75,7 +84,8 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
        rfkill->name = dev_name(dev);
        rfkill->type = (unsigned)id->driver_data;
 
-       return 0;
+       return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
+                                        acpi_rfkill_default_gpios);
 }
 
 static int rfkill_gpio_probe(struct platform_device *pdev)
@@ -102,7 +112,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
 
        rfkill->clk = devm_clk_get(&pdev->dev, NULL);
 
-       gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0);
+       gpio = devm_gpiod_get(&pdev->dev, "reset");
        if (!IS_ERR(gpio)) {
                ret = gpiod_direction_output(gpio, 0);
                if (ret)
@@ -110,7 +120,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
                rfkill->reset_gpio = gpio;
        }
 
-       gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1);
+       gpio = devm_gpiod_get(&pdev->dev, "shutdown");
        if (!IS_ERR(gpio)) {
                ret = gpiod_direction_output(gpio, 0);
                if (ret)
@@ -150,6 +160,8 @@ static int rfkill_gpio_remove(struct platform_device *pdev)
        rfkill_unregister(rfkill->rfkill_dev);
        rfkill_destroy(rfkill->rfkill_dev);
 
+       acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
+
        return 0;
 }
 
index b8960c4..200e378 100644 (file)
@@ -117,6 +117,7 @@ struct keyring_search_context {
 #define KEYRING_SEARCH_NO_UPDATE_TIME  0x0004  /* Don't update times */
 #define KEYRING_SEARCH_NO_CHECK_PERM   0x0008  /* Don't check permissions */
 #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010  /* Give an error on excessive depth */
+#define KEYRING_SEARCH_SKIP_EXPIRED    0x0020  /* Ignore expired keys (intention to replace) */
 
        int (*iterator)(const void *object, void *iterator_data);
 
index eff88a5..4743d71 100644 (file)
@@ -26,6 +26,8 @@
 #include <asm/uaccess.h>
 #include "internal.h"
 
+#define KEY_MAX_DESC_SIZE 4096
+
 static int key_get_type_from_user(char *type,
                                  const char __user *_type,
                                  unsigned len)
@@ -78,7 +80,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
 
        description = NULL;
        if (_description) {
-               description = strndup_user(_description, PAGE_SIZE);
+               description = strndup_user(_description, KEY_MAX_DESC_SIZE);
                if (IS_ERR(description)) {
                        ret = PTR_ERR(description);
                        goto error;
@@ -177,7 +179,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
                goto error;
 
        /* pull the description into kernel space */
-       description = strndup_user(_description, PAGE_SIZE);
+       description = strndup_user(_description, KEY_MAX_DESC_SIZE);
        if (IS_ERR(description)) {
                ret = PTR_ERR(description);
                goto error;
@@ -287,7 +289,7 @@ long keyctl_join_session_keyring(const char __user *_name)
        /* fetch the name from userspace */
        name = NULL;
        if (_name) {
-               name = strndup_user(_name, PAGE_SIZE);
+               name = strndup_user(_name, KEY_MAX_DESC_SIZE);
                if (IS_ERR(name)) {
                        ret = PTR_ERR(name);
                        goto error;
@@ -562,8 +564,9 @@ long keyctl_describe_key(key_serial_t keyid,
 {
        struct key *key, *instkey;
        key_ref_t key_ref;
-       char *tmpbuf;
+       char *infobuf;
        long ret;
+       int desclen, infolen;
 
        key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
        if (IS_ERR(key_ref)) {
@@ -586,38 +589,31 @@ long keyctl_describe_key(key_serial_t keyid,
        }
 
 okay:
-       /* calculate how much description we're going to return */
-       ret = -ENOMEM;
-       tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!tmpbuf)
-               goto error2;
-
        key = key_ref_to_ptr(key_ref);
+       desclen = strlen(key->description);
 
-       ret = snprintf(tmpbuf, PAGE_SIZE - 1,
-                      "%s;%d;%d;%08x;%s",
-                      key->type->name,
-                      from_kuid_munged(current_user_ns(), key->uid),
-                      from_kgid_munged(current_user_ns(), key->gid),
-                      key->perm,
-                      key->description ?: "");
-
-       /* include a NUL char at the end of the data */
-       if (ret > PAGE_SIZE - 1)
-               ret = PAGE_SIZE - 1;
-       tmpbuf[ret] = 0;
-       ret++;
+       /* calculate how much information we're going to return */
+       ret = -ENOMEM;
+       infobuf = kasprintf(GFP_KERNEL,
+                           "%s;%d;%d;%08x;",
+                           key->type->name,
+                           from_kuid_munged(current_user_ns(), key->uid),
+                           from_kgid_munged(current_user_ns(), key->gid),
+                           key->perm);
+       if (!infobuf)
+               goto error2;
+       infolen = strlen(infobuf);
+       ret = infolen + desclen + 1;
 
        /* consider returning the data */
-       if (buffer && buflen > 0) {
-               if (buflen > ret)
-                       buflen = ret;
-
-               if (copy_to_user(buffer, tmpbuf, buflen) != 0)
+       if (buffer && buflen >= ret) {
+               if (copy_to_user(buffer, infobuf, infolen) != 0 ||
+                   copy_to_user(buffer + infolen, key->description,
+                                desclen + 1) != 0)
                        ret = -EFAULT;
        }
 
-       kfree(tmpbuf);
+       kfree(infobuf);
 error2:
        key_ref_put(key_ref);
 error:
@@ -649,7 +645,7 @@ long keyctl_keyring_search(key_serial_t ringid,
        if (ret < 0)
                goto error;
 
-       description = strndup_user(_description, PAGE_SIZE);
+       description = strndup_user(_description, KEY_MAX_DESC_SIZE);
        if (IS_ERR(description)) {
                ret = PTR_ERR(description);
                goto error;
index 8177010..e72548b 100644 (file)
@@ -546,7 +546,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
                }
 
                if (key->expiry && ctx->now.tv_sec >= key->expiry) {
-                       ctx->result = ERR_PTR(-EKEYEXPIRED);
+                       if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
+                               ctx->result = ERR_PTR(-EKEYEXPIRED);
                        kleave(" = %d [expire]", ctx->skipped_ret);
                        goto skipped;
                }
@@ -628,6 +629,10 @@ static bool search_nested_keyrings(struct key *keyring,
               ctx->index_key.type->name,
               ctx->index_key.description);
 
+#define STATE_CHECKS (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_DO_STATE_CHECK)
+       BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
+              (ctx->flags & STATE_CHECKS) == STATE_CHECKS);
+
        if (ctx->index_key.description)
                ctx->index_key.desc_len = strlen(ctx->index_key.description);
 
@@ -637,7 +642,6 @@ static bool search_nested_keyrings(struct key *keyring,
        if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
            keyring_compare_object(keyring, &ctx->index_key)) {
                ctx->skipped_ret = 2;
-               ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
                switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) {
                case 1:
                        goto found;
@@ -649,8 +653,6 @@ static bool search_nested_keyrings(struct key *keyring,
        }
 
        ctx->skipped_ret = 0;
-       if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK)
-               ctx->flags &= ~KEYRING_SEARCH_DO_STATE_CHECK;
 
        /* Start processing a new keyring */
 descend_to_keyring:
index bb4337c..0c7aea4 100644 (file)
@@ -516,6 +516,8 @@ struct key *request_key_and_link(struct key_type *type,
                .match_data.cmp         = key_default_cmp,
                .match_data.raw_data    = description,
                .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = (KEYRING_SEARCH_DO_STATE_CHECK |
+                                          KEYRING_SEARCH_SKIP_EXPIRED),
        };
        struct key *key;
        key_ref_t key_ref;
index 6639e2c..5d672f7 100644 (file)
@@ -249,6 +249,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
                .match_data.cmp         = key_default_cmp,
                .match_data.raw_data    = description,
                .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_DO_STATE_CHECK,
        };
        struct key *authkey;
        key_ref_t authkey_ref;
index 14f16be..b118a5b 100644 (file)
@@ -4790,6 +4790,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),