Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 20 Dec 2016 23:48:34 +0000 (15:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 20 Dec 2016 23:48:34 +0000 (15:48 -0800)
Pull networking fixes and cleanups from David Miller:

 1) Use rb_entry() instead of hardcoded container_of(), from Geliang
    Tang.

 2) Use correct memory barriers in stammac driver, from Pavel Machek.

 3) Fix assoc bind address handling in SCTP, from Xin Long.

 4) Make the length check for UFO handling consistent between
    __ip_append_data() and ip_finish_output(), from Zheng Li.

 5) HSI driver compatible strings were busted fro hix5hd2, from Dongpo
    Li.

 6) Handle devm_ioremap() errors properly in cavium driver, from Arvind
    Yadav.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (22 commits)
  RDS: use rb_entry()
  net_sched: sch_netem: use rb_entry()
  net_sched: sch_fq: use rb_entry()
  net/mlx5: use rb_entry()
  ethernet: sfc: Add Kconfig entry for vendor Solarflare
  sctp: not copying duplicate addrs to the assoc's bind address list
  sctp: reduce indent level in sctp_copy_local_addr_list
  ARM: dts: hix5hd2: don't change the existing compatible string
  net: hix5hd2_gmac: fix compatible strings name
  openvswitch: Add a missing break statement.
  net: netcp: ethss: fix 10gbe host port tx pri map configuration
  net: netcp: ethss: fix errors in ethtool ops
  fsl/fman: enable compilation on ARM64
  fsl/fman: A007273 only applies to PPC SoCs
  powerpc: fsl/fman: remove fsl,fman from of_device_ids[]
  fsl/fman: fix 1G support for QSGMII interfaces
  dt: bindings: net: use boolean dt properties for eee broken modes
  net: phy: use boolean dt properties for eee broken modes
  net: phy: fix sign type error in genphy_config_eee_advert
  ipv4: Should use consistent conditional judgement for ip fragment in __ip_append_data and ip_finish_output
  ...

202 files changed:
Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration
Documentation/admin-guide/kernel-parameters.txt
Documentation/devicetree/bindings/mfd/altera-a10sr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt
Documentation/devicetree/bindings/mfd/rn5t618.txt
Documentation/devicetree/bindings/regulator/tps65218.txt
Documentation/devicetree/bindings/rtc/epson,rtc7301.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/twl-rtc.txt
Documentation/features/io/dma-api-debug/arch-support.txt
Documentation/features/io/dma-contiguous/arch-support.txt
Documentation/sphinx/rstFlatTable.py
Documentation/virtual/kvm/locking.txt
MAINTAINERS
arch/Kconfig
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/numa.h
arch/arm64/kernel/setup.c
arch/arm64/mm/numa.c
arch/ia64/include/asm/numa.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/include/uapi/asm/unistd.h
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/kernel/timer.c
arch/mips/boot/dts/ingenic/jz4740.dtsi
arch/mips/boot/dts/ingenic/qi_lb60.dts
arch/mips/include/asm/mach-jz4740/platform.h
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/jz4740/reset.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/ima.h [new file with mode: 0644]
arch/powerpc/include/asm/kexec.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/ima_kexec.c [new file with mode: 0644]
arch/powerpc/kernel/kexec_elf_64.c
arch/powerpc/kernel/machine_kexec_file_64.c
arch/x86/Kconfig
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/floppy.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mpx.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/tsc.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/head_64.S
arch/x86/kernel/process.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_msr.c
arch/x86/kernel/tsc_sync.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/fault.c
arch/x86/mm/init_64.c
arch/x86/mm/mpx.c
arch/x86/mm/numa.c
arch/x86/platform/Makefile
arch/x86/platform/intel-mid/mfld.c
arch/x86/platform/intel-mid/mrfld.c
arch/x86/platform/mellanox/Makefile [deleted file]
arch/x86/platform/mellanox/mlx-platform.c [deleted file]
arch/x86/power/cpu.c
arch/x86/xen/smp.c
arch/xtensa/Kconfig
arch/xtensa/boot/dts/kc705.dts
arch/xtensa/include/asm/Kbuild
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/pci-dma.c
arch/xtensa/kernel/s32c1i_selftest.c [new file with mode: 0644]
arch/xtensa/kernel/setup.c
arch/xtensa/mm/init.c
drivers/acpi/numa.c
drivers/dax/dax.c
drivers/dax/pmem.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-tps65218.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-octeon-core.c
drivers/i2c/busses/i2c-octeon-core.h
drivers/i2c/busses/i2c-xgene-slimpro.c
drivers/i2c/muxes/i2c-mux-mlxcpld.c
drivers/i2c/muxes/i2c-mux-pca954x.c
drivers/input/misc/tps65218-pwrbutton.c
drivers/mailbox/bcm-pdc-mailbox.c
drivers/mailbox/mailbox-sti.c
drivers/mailbox/mailbox-test.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3100-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/abx500-core.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-irq.c
drivers/mfd/axp20x-i2c.c
drivers/mfd/axp20x.c
drivers/mfd/bcm590xx.c
drivers/mfd/cs47l24-tables.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/fsl-imx25-tsadc.c
drivers/mfd/hi655x-pmic.c
drivers/mfd/intel-lpss-pci.c
drivers/mfd/intel_soc_pmic_bxtwc.c
drivers/mfd/lpc_ich.c
drivers/mfd/palmas.c
drivers/mfd/qcom-pm8xxx.c
drivers/mfd/rk808.c
drivers/mfd/rn5t618.c
drivers/mfd/si476x-i2c.c
drivers/mfd/sun4i-gpadc.c [new file with mode: 0644]
drivers/mfd/tc3589x.c
drivers/mfd/tps65217.c
drivers/mfd/tps65218.c
drivers/mfd/tps65912-core.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm8994-core.c
drivers/nvdimm/claim.c
drivers/nvdimm/core.c
drivers/nvdimm/dimm.c
drivers/nvdimm/dimm_devs.c
drivers/nvdimm/e820.c
drivers/nvdimm/label.c
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/nd.h
drivers/nvdimm/pfn_devs.c
drivers/nvdimm/pmem.c
drivers/nvdimm/region_devs.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_bxtwc_tmu.c [new file with mode: 0644]
drivers/platform/x86/mlx-platform.c [new file with mode: 0644]
drivers/platform/x86/surface3-wmi.c [new file with mode: 0644]
drivers/platform/x86/surface3_button.c [new file with mode: 0644]
drivers/regulator/tps65218-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lib.c
drivers/rtc/rtc-mcp795.c
drivers/rtc/rtc-pcf85063.c
drivers/rtc/rtc-r7301.c [new file with mode: 0644]
drivers/rtc/rtc-starfire.c
drivers/rtc/rtc-sun4v.c
drivers/rtc/rtc-twl.c
fs/ext2/inode.c
fs/notify/inode_mark.c
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/super.c
fs/quota/dquot.c
fs/quota/quota.c
fs/super.c
include/linux/cpuhotplug.h
include/linux/cpumask.h
include/linux/fs.h
include/linux/ima.h
include/linux/mfd/axp20x.h
include/linux/mfd/davinci_voicecodec.h
include/linux/mfd/intel_soc_pmic.h
include/linux/mfd/rk808.h
include/linux/mfd/rn5t618.h
include/linux/mfd/sun4i-gpadc.h [new file with mode: 0644]
include/linux/mfd/tps65217.h
include/linux/mfd/tps65218.h
include/linux/mfd/tps65912.h
include/linux/mm_types.h
include/linux/quota.h
include/linux/ratelimit.h
kernel/cpu.c
kernel/irq/affinity.c
kernel/kcov.c
kernel/kexec_file.c
kernel/time/tick-broadcast.c
lib/Kconfig.debug
mm/fadvise.c
security/integrity/ima/Kconfig
security/integrity/ima/Makefile
security/integrity/ima/ima.h
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_kexec.c [new file with mode: 0644]
security/integrity/ima/ima_main.c
security/integrity/ima/ima_queue.c
security/integrity/ima/ima_template.c
security/integrity/ima/ima_template_lib.c
tools/testing/nvdimm/test/nfit.c

index 4cf1e72222d9c449464c1f3cd07f2ac7508d9349..ec950c93e5c6998daf2ee497732f732a2182ec25 100644 (file)
@@ -1,8 +1,9 @@
-What:           Attribute for calibrating ST-Ericsson AB8500 Real Time Clock
+What:           /sys/class/rtc/rtc0/device/rtc_calibration
 Date:           Oct 2011
 KernelVersion:  3.0
 Contact:        Mark Godfrey <mark.godfrey@stericsson.com>
-Description:    The rtc_calibration attribute allows the userspace to
+Description:    Attribute for calibrating ST-Ericsson AB8500 Real Time Clock
+               The rtc_calibration attribute allows the userspace to
                 calibrate the AB8500.s 32KHz Real Time Clock.
                 Every 60 seconds the AB8500 will correct the RTC's value
                 by adding to it the value of this attribute.
index be2d6d0a03a486c340c85ed7ba73c59b22a6d41f..21e2d88637050b7a33f141e558fff43d3f23d0c9 100644 (file)
                        The builtin appraise policy appraises all files
                        owned by uid=0.
 
+       ima_canonical_fmt [IMA]
+                       Use the canonical format for the binary runtime
+                       measurements, instead of host native format.
+
        ima_hash=       [IMA]
                        Format: { md5 | sha1 | rmd160 | sha256 | sha384
                                   | sha512 | ... }
diff --git a/Documentation/devicetree/bindings/mfd/altera-a10sr.txt b/Documentation/devicetree/bindings/mfd/altera-a10sr.txt
new file mode 100644 (file)
index 0000000..ea151f2
--- /dev/null
@@ -0,0 +1,46 @@
+* Altera Arria10 Development Kit System Resource Chip
+
+Required parent device properties:
+- compatible           : "altr,a10sr"
+- spi-max-frequency    : Maximum SPI frequency.
+- reg                  : The SPI Chip Select address for the Arria10
+                         System Resource chip
+- interrupt-parent     : The parent interrupt controller.
+- interrupts           : The interrupt line the device is connected to.
+- interrupt-controller : Marks the device node as an interrupt controller.
+- #interrupt-cells     : The number of cells to describe an IRQ, should be 2.
+                           The first cell is the IRQ number.
+                           The second cell is the flags, encoded as trigger
+                           masks from ../interrupt-controller/interrupts.txt.
+
+The A10SR consists of these sub-devices:
+
+Device                   Description
+------                   ----------
+a10sr_gpio               GPIO Controller
+
+Arria10 GPIO
+Required Properties:
+- compatible        : Should be "altr,a10sr-gpio"
+- gpio-controller   : Marks the device node as a GPIO Controller.
+- #gpio-cells       : Should be two.  The first cell is the pin number and
+                      the second cell is used to specify flags.
+                      See ../gpio/gpio.txt for more information.
+
+Example:
+
+        resource-manager@0 {
+               compatible = "altr,a10sr";
+               reg = <0>;
+               spi-max-frequency = <100000>;
+               interrupt-parent = <&portb>;
+               interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+
+               a10sr_gpio: gpio-controller {
+                       compatible = "altr,a10sr-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+       };
index 37a088f9a648ec94e9d9f2046251d3993ff09ed7..9e5eba4a4f0d0ab8387c103007079702a6d278bd 100644 (file)
@@ -10,6 +10,7 @@ voltages and other various functionality to Qualcomm SoCs.
        Value type: <string>
        Definition: must be one of:
                    "qcom,pm8058"
+                   "qcom,pm8821"
                    "qcom,pm8921"
 
 - #address-cells:
index 9e6770b105c935f8932ba39fd3351f9f4628155f..65c23263cc5418db378215612f152f8d887613f7 100644 (file)
@@ -1,21 +1,25 @@
 * Ricoh RN5T567/RN5T618 PMIC
 
-Ricoh RN5T567/RN5T618 is a power management IC family which integrates
-3 to 4 step-down DCDC converters, 7 low-dropout regulators, GPIOs and
-a watchdog timer. The RN5T618 provides additionally a Li-ion battery
-charger, fuel gauge and an ADC. It can be controlled through an I2C
-interface.
+Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which
+integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators,
+GPIOs, and a watchdog timer. It can be controlled through an I2C interface.
+The RN5T618/RC5T619 provides additionally a Li-ion battery charger,
+fuel gauge, and an ADC.
+The RC5T619 additionnally includes USB charger detection and an RTC.
 
 Required properties:
  - compatible: must be one of
                "ricoh,rn5t567"
                "ricoh,rn5t618"
+               "ricoh,rc5t619"
  - reg: the I2C slave address of the device
 
 Sub-nodes:
  - regulators: the node is required if the regulator functionality is
    needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4
-   (RN5T567), LDO1, LDO2, LDO3, LDO4, LDO5, LDORTC1 and LDORTC2.
+   (RN5T567/RC5T619), LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, LDO8,
+   LDO9, LDO10, LDORTC1 and LDORTC2.
+   LDO7-10 are specific to RC5T619.
    The common bindings for each individual regulator can be found in:
    Documentation/devicetree/bindings/regulator/regulator.txt
 
index fccc1d24af58a51e5da9bfb3ec08d21ffab18b02..02f0e9bbfbf8a43a447ddb67d96924789dcd7618 100644 (file)
@@ -1,23 +1,78 @@
 TPS65218 family of regulators
 
 Required properties:
-For tps65218 regulators/LDOs
-- compatible:
-  - "ti,tps65218-dcdc1" for DCDC1
-  - "ti,tps65218-dcdc2" for DCDC2
-  - "ti,tps65218-dcdc3" for DCDC3
-  - "ti,tps65218-dcdc4" for DCDC4
-  - "ti,tps65218-dcdc5" for DCDC5
-  - "ti,tps65218-dcdc6" for DCDC6
-  - "ti,tps65218-ldo1" for LDO1
-
-Optional properties:
-- Any optional property defined in bindings/regulator/regulator.txt
+- compatible: "ti,tps65218"
+- reg: I2C slave address
+
+- List of regulators provided by this controller, must be named
+  after their hardware counterparts: dcdc[1-6] and ldo1
+- This is the list of child nodes that specify the regulator
+  initialization data for defined regulators. Not all regulators for the given
+  device need to be present. The definition for each of these nodes is defined
+  using the standard binding for regulators found at ./regulator.txt.
+
+  The valid names for regulators are:
+  tps65217: regulator-dcdc1, regulator-dcdc2, regulator-dcdc3, regulator-dcdc4,
+  regulator-dcdc5, regulator-dcdc6, regulator-ldo1, regulator-ls3.
+  Each regulator is defined using the standard binding for regulators.
 
 Example:
+tps65218: tps65218@24 {
+       reg = <0x24>;
+       compatible = "ti,tps65218";
+       interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* NMIn */
+       interrupt-controller;
+       #interrupt-cells = <2>;
+
+       dcdc1: regulator-dcdc1 {
+               regulator-name = "vdd_core";
+               regulator-min-microvolt = <912000>;
+               regulator-max-microvolt = <1144000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc2: regulator-dcdc2 {
+               regulator-name = "vdd_mpu";
+               regulator-min-microvolt = <912000>;
+               regulator-max-microvolt = <1378000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc3: regulator-dcdc3 {
+               regulator-name = "vdcdc3";
+               regulator-min-microvolt = <1500000>;
+               regulator-max-microvolt = <1500000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc5: regulator-dcdc5 {
+               regulator-name = "v1_0bat";
+               regulator-min-microvolt = <1000000>;
+               regulator-max-microvolt = <1000000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       dcdc6: regulator-dcdc6 {
+               regulator-name = "v1_8bat";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+
+       ldo1: regulator-ldo1 {
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
 
-       xyz: regulator@0 {
-               compatible = "ti,tps65218-dcdc1";
-               regulator-min-microvolt  = <1000000>;
-               regulator-max-microvolt  = <3000000>;
+       ls3: regulator-ls3 {
+               regulator-min-microvolt = <100000>;
+               regulator-max-microvolt = <1000000>;
        };
+};
diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt b/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt
new file mode 100644 (file)
index 0000000..5f9df3f
--- /dev/null
@@ -0,0 +1,16 @@
+EPSON TOYOCOM RTC-7301SF/DG
+
+Required properties:
+
+- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg"
+- reg: Specifies base physical address and size of the registers.
+- interrupts: A single interrupt specifier.
+
+Example:
+
+rtc: rtc@44a00000 {
+       compatible = "epson,rtc7301dg";
+       reg = <0x44a00000 0x10000>;
+       interrupt-parent = <&axi_intc_0>;
+       interrupts = <3 2>;
+};
diff --git a/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt b/Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt
new file mode 100644 (file)
index 0000000..41c7ae1
--- /dev/null
@@ -0,0 +1,37 @@
+JZ4740 and similar SoCs real-time clock driver
+
+Required properties:
+
+- compatible: One of:
+  - "ingenic,jz4740-rtc" - for use with the JZ4740 SoC
+  - "ingenic,jz4780-rtc" - for use with the JZ4780 SoC
+- reg: Address range of rtc register set
+- interrupts: IRQ number for the alarm interrupt
+- clocks: phandle to the "rtc" clock
+- clock-names: must be "rtc"
+
+Optional properties:
+- system-power-controller: To use this component as the
+  system power controller
+- reset-pin-assert-time-ms: Reset pin low-level assertion
+  time after wakeup (default 60ms; range 0-125ms if RTC clock
+  at 32 kHz)
+- min-wakeup-pin-assert-time-ms: Minimum wakeup pin assertion
+  time (default 100ms; range 0-2s if RTC clock at 32 kHz)
+
+Example:
+
+rtc@10003000 {
+       compatible = "ingenic,jz4740-rtc";
+       reg = <0x10003000 0x40>;
+
+       interrupt-parent = <&intc>;
+       interrupts = <32>;
+
+       clocks = <&rtc_clock>;
+       clock-names = "rtc";
+
+       system-power-controller;
+       reset-pin-assert-time-ms = <60>;
+       min-wakeup-pin-assert-time-ms = <100>;
+};
index 596e0c97be7aa318a5d2268e5d464b9b147dd7bf..8f9a94f2f8969911e4490b744563c180a413426b 100644 (file)
@@ -1,12 +1,11 @@
-* TI twl RTC
-
-The TWL family (twl4030/6030) contains a RTC.
+* Texas Instruments TWL4030/6030 RTC
 
 Required properties:
-- compatible : Should be twl4030-rtc
-
-Examples:
-
-rtc@0 {
-    compatible = "ti,twl4030-rtc";
-};
+- compatible : Should be "ti,twl4030-rtc"
+- interrupts : Should be the interrupt number.
+
+Example:
+       rtc {
+               compatible = "ti,twl4030-rtc";
+               interrupts = <11>;
+       };
index 4f4a3443b114c6ecd5a41856c86559daca0d51b6..ffa522a9bdfdcc34b017bc9a3e70be8fe2d87082 100644 (file)
@@ -36,5 +36,5 @@
     |          um: | TODO |
     |   unicore32: | TODO |
     |         x86: |  ok  |
-    |      xtensa: | TODO |
+    |      xtensa: |  ok  |
     -----------------------
index a97e8e3f4ebbed8d2467e19d6e736ef21f8f9991..83d2cf989ea3494dc825fc9e4da3b1ed09491646 100644 (file)
@@ -36,5 +36,5 @@
     |          um: | TODO |
     |   unicore32: | TODO |
     |         x86: |  ok  |
-    |      xtensa: | TODO |
+    |      xtensa: |  ok  |
     -----------------------
index 55f27579302830c4e07634c6b17e56f6fa14e227..25feb0d35e7abc7f6ff7797faf02e9e79321e644 100755 (executable)
@@ -157,6 +157,11 @@ class ListTableBuilder(object):
     def buildTableNode(self):
 
         colwidths    = self.directive.get_column_widths(self.max_cols)
+        if isinstance(colwidths, tuple):
+            # Since docutils 0.13, get_column_widths returns a (widths,
+            # colwidths) tuple, where widths is a string (i.e. 'auto').
+            # See https://sourceforge.net/p/docutils/patches/120/.
+            colwidths = colwidths[1]
         stub_columns = self.directive.options.get('stub-columns', 0)
         header_rows  = self.directive.options.get('header-rows', 0)
 
index e5dd9f4d61008ad6431e067b900608788e573020..fd013bf4115be70bafdb6489dc4caedf61e7600d 100644 (file)
@@ -13,8 +13,12 @@ The acquisition orders for mutexes are as follows:
 - kvm->slots_lock is taken outside kvm->irq_lock, though acquiring
   them together is quite rare.
 
-For spinlocks, kvm_lock is taken outside kvm->mmu_lock.  Everything
-else is a leaf: no other lock is taken inside the critical sections.
+On x86, vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock.
+
+For spinlocks, kvm_lock is taken outside kvm->mmu_lock.
+
+Everything else is a leaf: no other lock is taken inside the critical
+sections.
 
 2: Exception
 ------------
index f39414662ab6b1f9c500d607a7f896a78907db05..f6eb97b35e0fd58fe353cefce963ce7ff162491f 100644 (file)
@@ -8070,7 +8070,7 @@ MELLANOX PLATFORM DRIVER
 M:      Vadim Pasternak <vadimp@mellanox.com>
 L:      platform-driver-x86@vger.kernel.org
 S:      Supported
-F:      arch/x86/platform/mellanox/mlx-platform.c
+F:      drivers/platform/x86/mlx-platform.c
 
 MELLANOX MLX CPLD HOTPLUG DRIVER
 M:     Vadim Pasternak <vadimp@mellanox.com>
index 19483aea4bbc9e15b51f0bc7f200880902794a74..99839c23d453fa8ded2061968aead8a6ee4b2317 100644 (file)
@@ -5,6 +5,9 @@
 config KEXEC_CORE
        bool
 
+config HAVE_IMA_KEXEC
+       bool
+
 config OPROFILE
        tristate "OProfile system profiling"
        depends on PROFILING
index b71086d251954f7b72837899346525322dc5d724..bfe632808d7724c0a51562efb60501e67f6bf157 100644 (file)
@@ -165,6 +165,11 @@ extern u64                 kimage_vaddr;
 /* the offset between the kernel virtual and physical mappings */
 extern u64                     kimage_voffset;
 
+static inline unsigned long kaslr_offset(void)
+{
+       return kimage_vaddr - KIMAGE_VADDR;
+}
+
 /*
  * Allow all memory at the discovery stage. We will clip it later.
  */
index 600887e491fdf2af4ad30dcc0d1601908fcca087..bf466d1876e3f27d6cd2b6e7edced71c0ae32f7b 100644 (file)
@@ -15,6 +15,8 @@ int __node_distance(int from, int to);
 
 extern nodemask_t numa_nodes_parsed __initdata;
 
+extern bool numa_off;
+
 /* Mappings between node number and cpus on that node. */
 extern cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
 void numa_clear_node(unsigned int cpu);
index a53f52ac81c62ad4e6e70056949d143f7de4bfd4..b051367e21491cada86f115f4386fda8aace299a 100644 (file)
@@ -338,11 +338,11 @@ subsys_initcall(topology_init);
 static int dump_kernel_offset(struct notifier_block *self, unsigned long v,
                              void *p)
 {
-       u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR;
+       const unsigned long offset = kaslr_offset();
 
-       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) {
-               pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n",
-                        kaslr_offset, KIMAGE_VADDR);
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && offset > 0) {
+               pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",
+                        offset, KIMAGE_VADDR);
        } else {
                pr_emerg("Kernel Offset: disabled\n");
        }
index 4b32168cf91a0e3b99e1d899960d47fddf38ba06..b388a99fea7b783e5ab8edcad004f8a7457ee40e 100644 (file)
@@ -35,7 +35,7 @@ static int cpu_to_node_map[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
 
 static int numa_distance_cnt;
 static u8 *numa_distance;
-static bool numa_off;
+bool numa_off;
 
 static __init int numa_parse_early_param(char *opt)
 {
index 2db0a6c6daa5f13840bed1ede72c224e6dd5cf6a..ebef7f40aabbe26a5fa384294bf05819f949dd30 100644 (file)
@@ -65,6 +65,8 @@ extern int paddr_to_nid(unsigned long paddr);
 
 #define local_nodeid (cpu_to_node_map[smp_processor_id()])
 
+#define numa_off     0
+
 extern void map_cpu_to_node(int cpu, int nid);
 extern void unmap_cpu_from_node(int cpu, int nid);
 extern void numa_clear_node(int cpu);
index 805ae5d712e8baa63095199f1601ce548c26d606..032fed71223f54358a467d5df14d0b5fe176667a 100644 (file)
@@ -38,6 +38,6 @@
 
 #endif /* __ASSEMBLY__ */
 
-#define __NR_syscalls         392
+#define __NR_syscalls         398
 
 #endif /* _ASM_MICROBLAZE_UNISTD_H */
index a8bd3fa28bc7f4e97158fff49d25443524647b0d..d8086159d996dfdec4503fa95cf1638637f8932e 100644 (file)
 #define __NR_userfaultfd       389
 #define __NR_membarrier                390
 #define __NR_mlock2            391
+#define __NR_copy_file_range   392
+#define __NR_preadv2           393
+#define __NR_pwritev2          394
+#define __NR_pkey_mprotect     395
+#define __NR_pkey_alloc                396
+#define __NR_pkey_free         397
 
 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
index b70bb538f00165df2d46ec87c27217577ec4b95a..96b3f26d16beeb56b815da8d87661223e2beae91 100644 (file)
@@ -49,6 +49,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"9.3", 0x20},
        {"9.4", 0x21},
        {"9.5", 0x22},
+       {"9.6", 0x23},
+       {"10.0", 0x24},
        {NULL, 0},
 };
 
@@ -75,6 +77,10 @@ const struct family_string_key family_string_lookup[] = {
        {"zynq7000", 0x12},
        {"UltraScale Virtex", 0x13},
        {"UltraScale Kintex", 0x14},
+       {"UltraScale+ Zynq", 0x15},
+       {"UltraScale+ Virtex", 0x16},
+       {"UltraScale+ Kintex", 0x17},
+       {"Spartan7", 0x18},
        {NULL, 0},
 };
 
index 6b3dd99126d753a22a9ed270ec92761c2f936e27..6841c2df14d9acdfe30133baac0833111bf645d5 100644 (file)
@@ -392,3 +392,9 @@ ENTRY(sys_call_table)
        .long sys_userfaultfd
        .long sys_membarrier            /* 390 */
        .long sys_mlock2
+       .long sys_copy_file_range
+       .long sys_preadv2
+       .long sys_pwritev2
+       .long sys_pkey_mprotect         /* 395 */
+       .long sys_pkey_alloc
+       .long sys_pkey_free
index 5bbf38b916ef36839396c01cfd5bc105245ae934..9e954959f60504cd7cf04d1c8c58f897bf6cea76 100644 (file)
@@ -259,7 +259,7 @@ static int __init xilinx_timer_init(struct device_node *timer)
        int ret;
 
        if (initialized)
-               return;
+               return -EINVAL;
 
        initialized = 1;
 
index f6ae6ed9c4b1a3849ab078c273c0afa199734d45..3e1587f1f77a37e712f28e6fa61011dea25fc306 100644 (file)
                #clock-cells = <1>;
        };
 
+       rtc_dev: rtc@10003000 {
+               compatible = "ingenic,jz4740-rtc";
+               reg = <0x10003000 0x40>;
+
+               interrupt-parent = <&intc>;
+               interrupts = <15>;
+
+               clocks = <&cgu JZ4740_CLK_RTC>;
+               clock-names = "rtc";
+       };
+
        uart0: serial@10030000 {
                compatible = "ingenic,jz4740-uart";
                reg = <0x10030000 0x100>;
index 2414d63ae81898d35766c184862ad2bd6e27f41b..be1a7d3a3e1b5aa8819f702d6507c44116a1e1c7 100644 (file)
@@ -13,3 +13,7 @@
 &ext {
        clock-frequency = <12000000>;
 };
+
+&rtc_dev {
+       system-power-controller;
+};
index 073b8bfbb3b3f16525df19d9802b2d32897a9bcd..3645974b7f6595ed1f5d6729621b3763b4399e87 100644 (file)
@@ -22,7 +22,6 @@
 extern struct platform_device jz4740_udc_device;
 extern struct platform_device jz4740_udc_xceiv_device;
 extern struct platform_device jz4740_mmc_device;
-extern struct platform_device jz4740_rtc_device;
 extern struct platform_device jz4740_i2c_device;
 extern struct platform_device jz4740_nand_device;
 extern struct platform_device jz4740_framebuffer_device;
index 258fd03c9ef5aa98145cb69b699f39f5dd92e81a..a5bd94b952635fb9ebb9b23e115625d4db8c6da1 100644 (file)
@@ -438,7 +438,6 @@ static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_pcm_device,
        &jz4740_i2s_device,
        &jz4740_codec_device,
-       &jz4740_rtc_device,
        &jz4740_adc_device,
        &jz4740_pwm_device,
        &jz4740_dma_device,
index 2f1dab35c061831263073707d6ee6e4c07816c4f..5b7cdd67a9d95b624d52d780ab736f779e551904 100644 (file)
@@ -88,27 +88,6 @@ struct platform_device jz4740_mmc_device = {
        .resource       = jz4740_mmc_resources,
 };
 
-/* RTC controller */
-static struct resource jz4740_rtc_resources[] = {
-       {
-               .start  = JZ4740_RTC_BASE_ADDR,
-               .end    = JZ4740_RTC_BASE_ADDR + 0x38 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = JZ4740_IRQ_RTC,
-               .end    = JZ4740_IRQ_RTC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device jz4740_rtc_device = {
-       .name           = "jz4740-rtc",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(jz4740_rtc_resources),
-       .resource       = jz4740_rtc_resources,
-};
-
 /* I2C controller */
 static struct resource jz4740_i2c_resources[] = {
        {
index 954e669c9e6bc5d2b47f30a796e602a155dc5495..67780c4b65730597e6d66d08e238b44669456823 100644 (file)
@@ -57,71 +57,8 @@ static void jz4740_restart(char *command)
        jz4740_halt();
 }
 
-#define JZ_REG_RTC_CTRL                        0x00
-#define JZ_REG_RTC_HIBERNATE           0x20
-#define JZ_REG_RTC_WAKEUP_FILTER       0x24
-#define JZ_REG_RTC_RESET_COUNTER       0x28
-
-#define JZ_RTC_CTRL_WRDY               BIT(7)
-#define JZ_RTC_WAKEUP_FILTER_MASK      0x0000FFE0
-#define JZ_RTC_RESET_COUNTER_MASK      0x00000FE0
-
-static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base)
-{
-       uint32_t ctrl;
-
-       do {
-               ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
-       } while (!(ctrl & JZ_RTC_CTRL_WRDY));
-}
-
-static void jz4740_power_off(void)
-{
-       void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38);
-       unsigned long wakeup_filter_ticks;
-       unsigned long reset_counter_ticks;
-       struct clk *rtc_clk;
-       unsigned long rtc_rate;
-
-       rtc_clk = clk_get(NULL, "rtc");
-       if (IS_ERR(rtc_clk))
-               panic("unable to get RTC clock");
-       rtc_rate = clk_get_rate(rtc_clk);
-       clk_put(rtc_clk);
-
-       /*
-        * Set minimum wakeup pin assertion time: 100 ms.
-        * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
-        */
-       wakeup_filter_ticks = (100 * rtc_rate) / 1000;
-       if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
-               wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
-       else
-               wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
-       jz4740_rtc_wait_ready(rtc_base);
-       writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER);
-
-       /*
-        * Set reset pin low-level assertion time after wakeup: 60 ms.
-        * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
-        */
-       reset_counter_ticks = (60 * rtc_rate) / 1000;
-       if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
-               reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
-       else
-               reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
-       jz4740_rtc_wait_ready(rtc_base);
-       writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER);
-
-       jz4740_rtc_wait_ready(rtc_base);
-       writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
-
-       jz4740_halt();
-}
-
 void jz4740_reset_init(void)
 {
        _machine_restart = jz4740_restart;
        _machine_halt = jz4740_halt;
-       pm_power_off = jz4740_power_off;
 }
index 3da87e19887827f55f14bd47bca849bdc9a14492..a8ee573fe610bd5e2d8191b4dffb05e134a6d3c2 100644 (file)
@@ -469,6 +469,7 @@ config KEXEC
 config KEXEC_FILE
        bool "kexec file based system call"
        select KEXEC_CORE
+       select HAVE_IMA_KEXEC
        select BUILD_BIN2C
        depends on PPC64
        depends on CRYPTO=y
diff --git a/arch/powerpc/include/asm/ima.h b/arch/powerpc/include/asm/ima.h
new file mode 100644 (file)
index 0000000..2313bdf
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _ASM_POWERPC_IMA_H
+#define _ASM_POWERPC_IMA_H
+
+struct kimage;
+
+int ima_get_kexec_buffer(void **addr, size_t *size);
+int ima_free_kexec_buffer(void);
+
+#ifdef CONFIG_IMA
+void remove_ima_buffer(void *fdt, int chosen_node);
+#else
+static inline void remove_ima_buffer(void *fdt, int chosen_node) {}
+#endif
+
+#ifdef CONFIG_IMA_KEXEC
+int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
+                             size_t size);
+
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node);
+#else
+static inline int setup_ima_buffer(const struct kimage *image, void *fdt,
+                                  int chosen_node)
+{
+       remove_ima_buffer(fdt, chosen_node);
+       return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
+
+#endif /* _ASM_POWERPC_IMA_H */
index 6c3b71502fbcbcc6566790b6f910955668bc43aa..25668bc8cb2a4c621db3c4a8b332b8c2ef9882a4 100644 (file)
@@ -94,11 +94,22 @@ static inline bool kdump_in_progress(void)
 #ifdef CONFIG_KEXEC_FILE
 extern struct kexec_file_ops kexec_elf64_ops;
 
+#ifdef CONFIG_IMA_KEXEC
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+       phys_addr_t ima_buffer_addr;
+       size_t ima_buffer_size;
+};
+#endif
+
 int setup_purgatory(struct kimage *image, const void *slave_code,
                    const void *fdt, unsigned long kernel_load_addr,
                    unsigned long fdt_load_addr);
-int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
-                 unsigned long initrd_len, const char *cmdline);
+int setup_new_fdt(const struct kimage *image, void *fdt,
+                 unsigned long initrd_load_addr, unsigned long initrd_len,
+                 const char *cmdline);
+int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size);
 #endif /* CONFIG_KEXEC_FILE */
 
 #else /* !CONFIG_KEXEC_CORE */
index a3a6047fd39502b389d5854f203426b6e79456c1..23f8082d7bfad95f4c9fbb8201e3e58c3104928f 100644 (file)
@@ -112,6 +112,10 @@ obj-$(CONFIG_PCI_MSI)              += msi.o
 obj-$(CONFIG_KEXEC_CORE)       += machine_kexec.o crash.o \
                                   machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file_$(BITS).o kexec_elf_$(BITS).o
+ifeq ($(CONFIG_HAVE_IMA_KEXEC)$(CONFIG_IMA),yy)
+obj-y                          += ima_kexec.o
+endif
+
 obj-$(CONFIG_AUDIT)            += audit.o
 obj64-$(CONFIG_AUDIT)          += compat_audit.o
 
diff --git a/arch/powerpc/kernel/ima_kexec.c b/arch/powerpc/kernel/ima_kexec.c
new file mode 100644 (file)
index 0000000..5ea42c9
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Authors:
+ * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/of.h>
+#include <linux/memblock.h>
+#include <linux/libfdt.h>
+
+static int get_addr_size_cells(int *addr_cells, int *size_cells)
+{
+       struct device_node *root;
+
+       root = of_find_node_by_path("/");
+       if (!root)
+               return -EINVAL;
+
+       *addr_cells = of_n_addr_cells(root);
+       *size_cells = of_n_size_cells(root);
+
+       of_node_put(root);
+
+       return 0;
+}
+
+static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
+                              size_t *size)
+{
+       int ret, addr_cells, size_cells;
+
+       ret = get_addr_size_cells(&addr_cells, &size_cells);
+       if (ret)
+               return ret;
+
+       if (len < 4 * (addr_cells + size_cells))
+               return -ENOENT;
+
+       *addr = of_read_number(prop, addr_cells);
+       *size = of_read_number(prop + 4 * addr_cells, size_cells);
+
+       return 0;
+}
+
+/**
+ * ima_get_kexec_buffer - get IMA buffer from the previous kernel
+ * @addr:      On successful return, set to point to the buffer contents.
+ * @size:      On successful return, set to the buffer size.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int ima_get_kexec_buffer(void **addr, size_t *size)
+{
+       int ret, len;
+       unsigned long tmp_addr;
+       size_t tmp_size;
+       const void *prop;
+
+       prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
+       if (!prop)
+               return -ENOENT;
+
+       ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
+       if (ret)
+               return ret;
+
+       *addr = __va(tmp_addr);
+       *size = tmp_size;
+
+       return 0;
+}
+
+/**
+ * ima_free_kexec_buffer - free memory used by the IMA buffer
+ */
+int ima_free_kexec_buffer(void)
+{
+       int ret;
+       unsigned long addr;
+       size_t size;
+       struct property *prop;
+
+       prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
+       if (!prop)
+               return -ENOENT;
+
+       ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
+       if (ret)
+               return ret;
+
+       ret = of_remove_property(of_chosen, prop);
+       if (ret)
+               return ret;
+
+       return memblock_free(addr, size);
+
+}
+
+/**
+ * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
+ *
+ * The IMA measurement buffer is of no use to a subsequent kernel, so we always
+ * remove it from the device tree.
+ */
+void remove_ima_buffer(void *fdt, int chosen_node)
+{
+       int ret, len;
+       unsigned long addr;
+       size_t size;
+       const void *prop;
+
+       prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
+       if (!prop)
+               return;
+
+       ret = do_get_kexec_buffer(prop, len, &addr, &size);
+       fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
+       if (ret)
+               return;
+
+       ret = delete_fdt_mem_rsv(fdt, addr, size);
+       if (!ret)
+               pr_debug("Removed old IMA buffer reservation.\n");
+}
+
+#ifdef CONFIG_IMA_KEXEC
+/**
+ * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer
+ *
+ * Architectures should use this function to pass on the IMA buffer
+ * information to the next kernel.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
+                             size_t size)
+{
+       image->arch.ima_buffer_addr = load_addr;
+       image->arch.ima_buffer_size = size;
+
+       return 0;
+}
+
+static int write_number(void *p, u64 value, int cells)
+{
+       if (cells == 1) {
+               u32 tmp;
+
+               if (value > U32_MAX)
+                       return -EINVAL;
+
+               tmp = cpu_to_be32(value);
+               memcpy(p, &tmp, sizeof(tmp));
+       } else if (cells == 2) {
+               u64 tmp;
+
+               tmp = cpu_to_be64(value);
+               memcpy(p, &tmp, sizeof(tmp));
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * setup_ima_buffer - add IMA buffer information to the fdt
+ * @image:             kexec image being loaded.
+ * @fdt:               Flattened device tree for the next kernel.
+ * @chosen_node:       Offset to the chosen node.
+ *
+ * Return: 0 on success, or negative errno on error.
+ */
+int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
+{
+       int ret, addr_cells, size_cells, entry_size;
+       u8 value[16];
+
+       remove_ima_buffer(fdt, chosen_node);
+       if (!image->arch.ima_buffer_size)
+               return 0;
+
+       ret = get_addr_size_cells(&addr_cells, &size_cells);
+       if (ret)
+               return ret;
+
+       entry_size = 4 * (addr_cells + size_cells);
+
+       if (entry_size > sizeof(value))
+               return -EINVAL;
+
+       ret = write_number(value, image->arch.ima_buffer_addr, addr_cells);
+       if (ret)
+               return ret;
+
+       ret = write_number(value + 4 * addr_cells, image->arch.ima_buffer_size,
+                          size_cells);
+       if (ret)
+               return ret;
+
+       ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value,
+                         entry_size);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = fdt_add_mem_rsv(fdt, image->arch.ima_buffer_addr,
+                             image->arch.ima_buffer_size);
+       if (ret)
+               return -EINVAL;
+
+       pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
+                image->arch.ima_buffer_addr, image->arch.ima_buffer_size);
+
+       return 0;
+}
+#endif /* CONFIG_IMA_KEXEC */
index 6acffd34a70f302fb020317c3cc56bf2564beb68..9a42309b091a67c7a6bd9d62133e48f34e8e94eb 100644 (file)
@@ -627,7 +627,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
                goto out;
        }
 
-       ret = setup_new_fdt(fdt, initrd_load_addr, initrd_len, cmdline);
+       ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline);
        if (ret)
                goto out;
 
index 7abc8a75ee48cbf8b6e3bbb7f639ef9e45da06db..992c0d258e5d564c3b57526e968b26e78bb9292d 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
+#include <asm/ima.h>
 
 #define SLAVE_CODE_SIZE                256
 
@@ -180,7 +181,7 @@ int setup_purgatory(struct kimage *image, const void *slave_code,
  *
  * Return: 0 on success, or negative errno on error.
  */
-static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
+int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
 {
        int i, ret, num_rsvs = fdt_num_mem_rsv(fdt);
 
@@ -209,6 +210,7 @@ static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size
 
 /*
  * setup_new_fdt - modify /chosen and memory reservation for the next kernel
+ * @image:             kexec image being loaded.
  * @fdt:               Flattened device tree for the next kernel.
  * @initrd_load_addr:  Address where the next initrd will be loaded.
  * @initrd_len:                Size of the next initrd, or 0 if there will be none.
@@ -217,8 +219,9 @@ static int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size
  *
  * Return: 0 on success, or negative errno on error.
  */
-int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
-                 unsigned long initrd_len, const char *cmdline)
+int setup_new_fdt(const struct kimage *image, void *fdt,
+                 unsigned long initrd_load_addr, unsigned long initrd_len,
+                 const char *cmdline)
 {
        int ret, chosen_node;
        const void *prop;
@@ -328,6 +331,12 @@ int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
                }
        }
 
+       ret = setup_ima_buffer(image, fdt, chosen_node);
+       if (ret) {
+               pr_err("Error setting up the new device tree.\n");
+               return ret;
+       }
+
        ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
        if (ret) {
                pr_err("Error setting up the new device tree.\n");
index dd47e60aabf5769a30d5944cd0811de4acdb2433..64024c9995314a9488bb83261baa1d6f7a9b5cae 100644 (file)
@@ -555,18 +555,6 @@ config X86_INTEL_QUARK
          Say Y here if you have a Quark based system such as the Arduino
          compatible Intel Galileo.
 
-config MLX_PLATFORM
-       tristate "Mellanox Technologies platform support"
-       depends on X86_64
-       depends on X86_EXTENDED_PLATFORM
-       ---help---
-         This option enables system support for the Mellanox Technologies
-         platform.
-
-         Say Y here if you are building a kernel for Mellanox system.
-
-         Otherwise, say N.
-
 config X86_INTEL_LPSS
        bool "Intel Low Power Subsystem Support"
        depends on X86 && ACPI
index 59ac427960d4dcfdc9eb13c2a171fa33f22b79fd..6ccbf1aaa7ce1f72021757593c99b555480f78da 100644 (file)
 #define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
 #define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
 #define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
+#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* TSC has known frequency */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3       ( 4*32+ 0) /* "pni" SSE-3 */
index 1c7eefe3250295762c258a66af22a05d53882334..7ec59edde154c344cb5bfce7ba586360a6d32d19 100644 (file)
@@ -229,18 +229,18 @@ static struct fd_routine_l {
        int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
 } fd_routine[] = {
        {
-               request_dma,
-               free_dma,
-               get_dma_residue,
-               dma_mem_alloc,
-               hard_dma_setup
+               ._request_dma           = request_dma,
+               ._free_dma              = free_dma,
+               ._get_dma_residue       = get_dma_residue,
+               ._dma_mem_alloc         = dma_mem_alloc,
+               ._dma_setup             = hard_dma_setup
        },
        {
-               vdma_request_dma,
-               vdma_nop,
-               vdma_get_dma_residue,
-               vdma_mem_alloc,
-               vdma_dma_setup
+               ._request_dma           = vdma_request_dma,
+               ._free_dma              = vdma_nop,
+               ._get_dma_residue       = vdma_get_dma_residue,
+               ._dma_mem_alloc         = vdma_mem_alloc,
+               ._dma_setup             = vdma_dma_setup
        }
 };
 
index 7892530cbacfb38e81684b1c5e60f90662e0d872..2e25038dbd932cfec9381eccbc1f4c30fe0c7b2e 100644 (file)
@@ -704,6 +704,7 @@ struct kvm_apic_map {
 
 /* Hyper-V emulation context */
 struct kvm_hv {
+       struct mutex hv_lock;
        u64 hv_guest_os_id;
        u64 hv_hypercall;
        u64 hv_tsc_page;
index 72198c64e646d3cbb0d9831d950e4e815003cdd3..f9813b6d8b806eae92363b5c5667c94ca5c9fd24 100644 (file)
@@ -31,6 +31,10 @@ typedef struct {
        u16 pkey_allocation_map;
        s16 execute_only_pkey;
 #endif
+#ifdef CONFIG_X86_INTEL_MPX
+       /* address of the bounds directory */
+       void __user *bd_addr;
+#endif
 } mm_context_t;
 
 #ifdef CONFIG_SMP
index 7a35495275a9b7b1150bde2935757a212defde59..0b416d4cf73b690a77b866ff461b5cf5ccbc2452 100644 (file)
@@ -59,7 +59,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs);
 int mpx_handle_bd_fault(void);
 static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
 {
-       return (mm->bd_addr != MPX_INVALID_BOUNDS_DIR);
+       return (mm->context.bd_addr != MPX_INVALID_BOUNDS_DIR);
 }
 static inline void mpx_mm_init(struct mm_struct *mm)
 {
@@ -67,7 +67,7 @@ static inline void mpx_mm_init(struct mm_struct *mm)
         * NULL is theoretically a valid place to put the bounds
         * directory, so point this at an invalid address.
         */
-       mm->bd_addr = MPX_INVALID_BOUNDS_DIR;
+       mm->context.bd_addr = MPX_INVALID_BOUNDS_DIR;
 }
 void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
                      unsigned long start, unsigned long end);
index 1cc82ece9ac1819b92ec82aca72805c0e966af97..62b775926045edb68aa935d7142067e2c00a03bd 100644 (file)
@@ -116,8 +116,7 @@ static inline void native_pgd_clear(pgd_t *pgd)
        native_set_pgd(pgd, native_make_pgd(0));
 }
 
-extern void sync_global_pgds(unsigned long start, unsigned long end,
-                            int removed);
+extern void sync_global_pgds(unsigned long start, unsigned long end);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
index 33b6365c22fed29b7081f637fd96b0b78a5c2162..abb1fdcc545a530f59880b3e7e754cf6034bf9a2 100644 (file)
@@ -45,8 +45,17 @@ extern int tsc_clocksource_reliable;
  * Boot-time check whether the TSCs are synchronized across
  * all CPUs/cores:
  */
+#ifdef CONFIG_X86_TSC
+extern bool tsc_store_and_check_tsc_adjust(bool bootcpu);
+extern void tsc_verify_tsc_adjust(bool resume);
 extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
+#else
+static inline bool tsc_store_and_check_tsc_adjust(bool bootcpu) { return false; }
+static inline void tsc_verify_tsc_adjust(bool resume) { }
+static inline void check_tsc_sync_source(int cpu) { }
+static inline void check_tsc_sync_target(void) { }
+#endif
 
 extern int notsc_setup(char *);
 extern void tsc_save_sched_clock_state(void);
index 05110c1097ae0a9ba9ddd3b7936b84ac3980def9..581386c7e42953e654ee60fda2feb0941c4e9c99 100644 (file)
@@ -75,7 +75,7 @@ apm-y                         := apm_32.o
 obj-$(CONFIG_APM)              += apm.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SMP)              += smpboot.o
-obj-$(CONFIG_SMP)              += tsc_sync.o
+obj-$(CONFIG_X86_TSC)          += tsc_sync.o
 obj-$(CONFIG_SMP)              += setup_percpu.o
 obj-$(CONFIG_X86_MPPARSE)      += mpparse.o
 obj-y                          += apic/
index 4764fa56924d200c724473a1c02a9823b56b5912..6f65b0eed384c6b276d26b44aeb0c535d6b9db3e 100644 (file)
@@ -715,7 +715,7 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
        int nid;
 
        nid = acpi_get_node(handle);
-       if (nid != -1) {
+       if (nid != NUMA_NO_NODE) {
                set_apicid_to_node(physid, nid);
                numa_set_node(cpu, nid);
        }
index bb47e5eacd448e0945d08ef7349d658459c02185..5b7e43eff139b888bb757c5c7ce3172017c5158b 100644 (file)
@@ -2159,21 +2159,6 @@ int __generic_processor_info(int apicid, int version, bool enabled)
                }
        }
 
-       /*
-        * This can happen on physical hotplug. The sanity check at boot time
-        * is done from native_smp_prepare_cpus() after num_possible_cpus() is
-        * established.
-        */
-       if (topology_update_package_map(apicid, cpu) < 0) {
-               int thiscpu = max + disabled_cpus;
-
-               pr_warning("APIC: Package limit reached. Processor %d/0x%x ignored.\n",
-                          thiscpu, apicid);
-
-               disabled_cpus++;
-               return -ENOSPC;
-       }
-
        /*
         * Validate version
         */
index 729f92ba8224b5682677fcf8e7a0821e993cdb10..1f6b50a449ab92820cdb9d90661d7c63eaba30c2 100644 (file)
@@ -979,29 +979,21 @@ static void x86_init_cache_qos(struct cpuinfo_x86 *c)
 }
 
 /*
- * The physical to logical package id mapping is initialized from the
- * acpi/mptables information. Make sure that CPUID actually agrees with
- * that.
+ * Validate that ACPI/mptables have the same information about the
+ * effective APIC id and update the package map.
  */
-static void sanitize_package_id(struct cpuinfo_x86 *c)
+static void validate_apic_and_package_id(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
-       unsigned int pkg, apicid, cpu = smp_processor_id();
+       unsigned int apicid, cpu = smp_processor_id();
 
        apicid = apic->cpu_present_to_apicid(cpu);
-       pkg = apicid >> boot_cpu_data.x86_coreid_bits;
 
-       if (apicid != c->initial_apicid) {
-               pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x CPUID: %x\n",
+       if (apicid != c->apicid) {
+               pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x APIC: %x\n",
                       cpu, apicid, c->initial_apicid);
-               c->initial_apicid = apicid;
        }
-       if (pkg != c->phys_proc_id) {
-               pr_err(FW_BUG "CPU%u: Using firmware package id %u instead of %u\n",
-                      cpu, pkg, c->phys_proc_id);
-               c->phys_proc_id = pkg;
-       }
-       c->logical_proc_id = topology_phys_to_logical_pkg(pkg);
+       BUG_ON(topology_update_package_map(c->phys_proc_id, cpu));
 #else
        c->logical_proc_id = 0;
 #endif
@@ -1132,7 +1124,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 #ifdef CONFIG_NUMA
        numa_add_cpu(smp_processor_id());
 #endif
-       sanitize_package_id(c);
 }
 
 /*
@@ -1187,6 +1178,7 @@ void identify_secondary_cpu(struct cpuinfo_x86 *c)
        enable_sep_cpu();
 #endif
        mtrr_ap_init();
+       validate_apic_and_package_id(c);
 }
 
 static __init int setup_noclflush(char *arg)
index 90de28841242a4992f23a304e6a048293f43b9af..b467b14b03eb2108bd7097065ed55aeae8121fc6 100644 (file)
@@ -298,12 +298,13 @@ ENTRY(start_cpu)
         *      REX.W + FF /5 JMP m16:64 Jump far, absolute indirect,
         *              address given in m16:64.
         */
-       call    1f              # put return address on stack for unwinder
-1:     xorq    %rbp, %rbp      # clear frame pointer
+       pushq   $.Lafter_lret   # put return address on stack for unwinder
+       xorq    %rbp, %rbp      # clear frame pointer
        movq    initial_code(%rip), %rax
        pushq   $__KERNEL_CS    # set correct cs
        pushq   %rax            # target address in negative space
        lretq
+.Lafter_lret:
 ENDPROC(start_cpu)
 
 #include "verify_cpu.S"
index 43c36d8a6ae25b43a90610dcf3079633792f8aed..37363e46b1f0beda54e6591583256c11e56cedee 100644 (file)
@@ -235,6 +235,7 @@ static inline void play_dead(void)
 
 void arch_cpu_idle_enter(void)
 {
+       tsc_verify_tsc_adjust(false);
        local_touch_nmi();
 }
 
index 0c37d4fd01b2649d0129c4c9edecefea80ab542a..46732dc3b73cd67e874dfe99b0eeb807f816e06a 100644 (file)
@@ -103,7 +103,6 @@ static unsigned int max_physical_pkg_id __read_mostly;
 unsigned int __max_logical_packages __read_mostly;
 EXPORT_SYMBOL(__max_logical_packages);
 static unsigned int logical_packages __read_mostly;
-static bool logical_packages_frozen __read_mostly;
 
 /* Maximum number of SMT threads on any online core */
 int __max_smt_threads __read_mostly;
@@ -273,9 +272,14 @@ static void notrace start_secondary(void *unused)
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
-int topology_update_package_map(unsigned int apicid, unsigned int cpu)
+/**
+ * topology_update_package_map - Update the physical to logical package map
+ * @pkg:       The physical package id as retrieved via CPUID
+ * @cpu:       The cpu for which this is updated
+ */
+int topology_update_package_map(unsigned int pkg, unsigned int cpu)
 {
-       unsigned int new, pkg = apicid >> boot_cpu_data.x86_coreid_bits;
+       unsigned int new;
 
        /* Called from early boot ? */
        if (!physical_package_map)
@@ -288,16 +292,17 @@ int topology_update_package_map(unsigned int apicid, unsigned int cpu)
        if (test_and_set_bit(pkg, physical_package_map))
                goto found;
 
-       if (logical_packages_frozen) {
-               physical_to_logical_pkg[pkg] = -1;
-               pr_warn("APIC(%x) Package %u exceeds logical package max\n",
-                       apicid, pkg);
+       if (logical_packages >= __max_logical_packages) {
+               pr_warn("Package %u of CPU %u exceeds BIOS package data %u.\n",
+                       logical_packages, cpu, __max_logical_packages);
                return -ENOSPC;
        }
 
        new = logical_packages++;
-       pr_info("APIC(%x) Converting physical %u to logical package %u\n",
-               apicid, pkg, new);
+       if (new != pkg) {
+               pr_info("CPU %u Converting physical %u to logical package %u\n",
+                       cpu, pkg, new);
+       }
        physical_to_logical_pkg[pkg] = new;
 
 found:
@@ -318,9 +323,9 @@ int topology_phys_to_logical_pkg(unsigned int phys_pkg)
 }
 EXPORT_SYMBOL(topology_phys_to_logical_pkg);
 
-static void __init smp_init_package_map(void)
+static void __init smp_init_package_map(struct cpuinfo_x86 *c, unsigned int cpu)
 {
-       unsigned int ncpus, cpu;
+       unsigned int ncpus;
        size_t size;
 
        /*
@@ -365,27 +370,9 @@ static void __init smp_init_package_map(void)
        size = BITS_TO_LONGS(max_physical_pkg_id) * sizeof(unsigned long);
        physical_package_map = kzalloc(size, GFP_KERNEL);
 
-       for_each_present_cpu(cpu) {
-               unsigned int apicid = apic->cpu_present_to_apicid(cpu);
-
-               if (apicid == BAD_APICID || !apic->apic_id_valid(apicid))
-                       continue;
-               if (!topology_update_package_map(apicid, cpu))
-                       continue;
-               pr_warn("CPU %u APICId %x disabled\n", cpu, apicid);
-               per_cpu(x86_bios_cpu_apicid, cpu) = BAD_APICID;
-               set_cpu_possible(cpu, false);
-               set_cpu_present(cpu, false);
-       }
-
-       if (logical_packages > __max_logical_packages) {
-               pr_warn("Detected more packages (%u), then computed by BIOS data (%u).\n",
-                       logical_packages, __max_logical_packages);
-               logical_packages_frozen = true;
-               __max_logical_packages  = logical_packages;
-       }
-
        pr_info("Max logical packages: %u\n", __max_logical_packages);
+
+       topology_update_package_map(c->phys_proc_id, cpu);
 }
 
 void __init smp_store_boot_cpu_info(void)
@@ -395,7 +382,7 @@ void __init smp_store_boot_cpu_info(void)
 
        *c = boot_cpu_data;
        c->cpu_index = id;
-       smp_init_package_map();
+       smp_init_package_map(c, id);
 }
 
 /*
@@ -1476,15 +1463,15 @@ __init void prefill_possible_map(void)
                possible = i;
        }
 
+       nr_cpu_ids = possible;
+
        pr_info("Allowing %d CPUs, %d hotplug CPUs\n",
                possible, max_t(int, possible - num_processors, 0));
 
+       reset_cpu_possible_mask();
+
        for (i = 0; i < possible; i++)
                set_cpu_possible(i, true);
-       for (; i < NR_CPUS; i++)
-               set_cpu_possible(i, false);
-
-       nr_cpu_ids = possible;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 46b2f41f8b05295cb782896da635c2c4c8687507..0aed75a1e31b0e7f88d3f3f105ea4207f5bcade2 100644 (file)
@@ -702,6 +702,20 @@ unsigned long native_calibrate_tsc(void)
                }
        }
 
+       /*
+        * TSC frequency determined by CPUID is a "hardware reported"
+        * frequency and is the most accurate one so far we have. This
+        * is considered a known frequency.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+
+       /*
+        * For Atom SoCs TSC is the only reliable clocksource.
+        * Mark TSC reliable so no watchdog on it.
+        */
+       if (boot_cpu_data.x86_model == INTEL_FAM6_ATOM_GOLDMONT)
+               setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
+
        return crystal_khz * ebx_numerator / eax_denominator;
 }
 
@@ -1043,18 +1057,20 @@ static void detect_art(void)
        if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
                return;
 
-       cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
-             &art_to_tsc_numerator, unused, unused+1);
-
-       /* Don't enable ART in a VM, non-stop TSC required */
+       /* Don't enable ART in a VM, non-stop TSC and TSC_ADJUST required */
        if (boot_cpu_has(X86_FEATURE_HYPERVISOR) ||
            !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
-           art_to_tsc_denominator < ART_MIN_DENOMINATOR)
+           !boot_cpu_has(X86_FEATURE_TSC_ADJUST))
                return;
 
-       if (rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset))
+       cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
+             &art_to_tsc_numerator, unused, unused+1);
+
+       if (art_to_tsc_denominator < ART_MIN_DENOMINATOR)
                return;
 
+       rdmsrl(MSR_IA32_TSC_ADJUST, art_to_tsc_offset);
+
        /* Make this sticky over multiple CPU init calls */
        setup_force_cpu_cap(X86_FEATURE_ART);
 }
@@ -1064,6 +1080,11 @@ static void detect_art(void)
 
 static struct clocksource clocksource_tsc;
 
+static void tsc_resume(struct clocksource *cs)
+{
+       tsc_verify_tsc_adjust(true);
+}
+
 /*
  * We used to compare the TSC to the cycle_last value in the clocksource
  * structure to avoid a nasty time-warp. This can be observed in a
@@ -1096,6 +1117,7 @@ static struct clocksource clocksource_tsc = {
        .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
                                  CLOCK_SOURCE_MUST_VERIFY,
        .archdata               = { .vclock_mode = VCLOCK_TSC },
+       .resume                 = tsc_resume,
 };
 
 void mark_tsc_unstable(char *reason)
@@ -1283,10 +1305,10 @@ static int __init init_tsc_clocksource(void)
                clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
 
        /*
-        * Trust the results of the earlier calibration on systems
-        * exporting a reliable TSC.
+        * When TSC frequency is known (retrieved via MSR or CPUID), we skip
+        * the refined calibration and directly register it as a clocksource.
         */
-       if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
+       if (boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) {
                clocksource_register_khz(&clocksource_tsc, tsc_khz);
                return 0;
        }
@@ -1363,6 +1385,8 @@ void __init tsc_init(void)
 
        if (unsynchronized_tsc())
                mark_tsc_unstable("TSCs unsynchronized");
+       else
+               tsc_store_and_check_tsc_adjust(true);
 
        check_system_tsc_reliable();
 
index 0fe720d64feff2c7027280f741495f6a9cf4722c..19afdbd7d0a77c8f5511cf2de616d24c5259dbae 100644 (file)
@@ -100,5 +100,24 @@ unsigned long cpu_khz_from_msr(void)
 #ifdef CONFIG_X86_LOCAL_APIC
        lapic_timer_frequency = (freq * 1000) / HZ;
 #endif
+
+       /*
+        * TSC frequency determined by MSR is always considered "known"
+        * because it is reported by HW.
+        * Another fact is that on MSR capable platforms, PIT/HPET is
+        * generally not available so calibration won't work at all.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+
+       /*
+        * Unfortunately there is no way for hardware to tell whether the
+        * TSC is reliable.  We were told by silicon design team that TSC
+        * on Atom SoCs are always "reliable". TSC is also the only
+        * reliable clocksource on these SoCs (HPET is either not present
+        * or not functional) so mark TSC reliable which removes the
+        * requirement for a watchdog clocksource.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
+
        return res;
 }
index 78083bf23ed1abc808c7699f383b58581bc72c1e..d0db011051a54212742680d3f25c2c52fb5c8ea6 100644 (file)
  * ( The serial nature of the boot logic and the CPU hotplug lock
  *   protects against more than 2 CPUs entering this code. )
  */
+#include <linux/topology.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/nmi.h>
 #include <asm/tsc.h>
 
+struct tsc_adjust {
+       s64             bootval;
+       s64             adjusted;
+       unsigned long   nextcheck;
+       bool            warned;
+};
+
+static DEFINE_PER_CPU(struct tsc_adjust, tsc_adjust);
+
+void tsc_verify_tsc_adjust(bool resume)
+{
+       struct tsc_adjust *adj = this_cpu_ptr(&tsc_adjust);
+       s64 curval;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               return;
+
+       /* Rate limit the MSR check */
+       if (!resume && time_before(jiffies, adj->nextcheck))
+               return;
+
+       adj->nextcheck = jiffies + HZ;
+
+       rdmsrl(MSR_IA32_TSC_ADJUST, curval);
+       if (adj->adjusted == curval)
+               return;
+
+       /* Restore the original value */
+       wrmsrl(MSR_IA32_TSC_ADJUST, adj->adjusted);
+
+       if (!adj->warned || resume) {
+               pr_warn(FW_BUG "TSC ADJUST differs: CPU%u %lld --> %lld. Restoring\n",
+                       smp_processor_id(), adj->adjusted, curval);
+               adj->warned = true;
+       }
+}
+
+static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval,
+                                  unsigned int cpu, bool bootcpu)
+{
+       /*
+        * First online CPU in a package stores the boot value in the
+        * adjustment value. This value might change later via the sync
+        * mechanism. If that fails we still can yell about boot values not
+        * being consistent.
+        *
+        * On the boot cpu we just force set the ADJUST value to 0 if it's
+        * non zero. We don't do that on non boot cpus because physical
+        * hotplug should have set the ADJUST register to a value > 0 so
+        * the TSC is in sync with the already running cpus.
+        *
+        * But we always force positive ADJUST values. Otherwise the TSC
+        * deadline timer creates an interrupt storm. We also have to
+        * prevent values > 0x7FFFFFFF as those wreckage the timer as well.
+        */
+       if ((bootcpu && bootval != 0) || (!bootcpu && bootval < 0) ||
+           (bootval > 0x7FFFFFFF)) {
+               pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu,
+                       bootval);
+               wrmsrl(MSR_IA32_TSC_ADJUST, 0);
+               bootval = 0;
+       }
+       cur->adjusted = bootval;
+}
+
+#ifndef CONFIG_SMP
+bool __init tsc_store_and_check_tsc_adjust(bool bootcpu)
+{
+       struct tsc_adjust *cur = this_cpu_ptr(&tsc_adjust);
+       s64 bootval;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               return false;
+
+       rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
+       cur->bootval = bootval;
+       cur->nextcheck = jiffies + HZ;
+       tsc_sanitize_first_cpu(cur, bootval, smp_processor_id(), bootcpu);
+       return false;
+}
+
+#else /* !CONFIG_SMP */
+
+/*
+ * Store and check the TSC ADJUST MSR if available
+ */
+bool tsc_store_and_check_tsc_adjust(bool bootcpu)
+{
+       struct tsc_adjust *ref, *cur = this_cpu_ptr(&tsc_adjust);
+       unsigned int refcpu, cpu = smp_processor_id();
+       struct cpumask *mask;
+       s64 bootval;
+
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               return false;
+
+       rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
+       cur->bootval = bootval;
+       cur->nextcheck = jiffies + HZ;
+       cur->warned = false;
+
+       /*
+        * Check whether this CPU is the first in a package to come up. In
+        * this case do not check the boot value against another package
+        * because the new package might have been physically hotplugged,
+        * where TSC_ADJUST is expected to be different. When called on the
+        * boot CPU topology_core_cpumask() might not be available yet.
+        */
+       mask = topology_core_cpumask(cpu);
+       refcpu = mask ? cpumask_any_but(mask, cpu) : nr_cpu_ids;
+
+       if (refcpu >= nr_cpu_ids) {
+               tsc_sanitize_first_cpu(cur, bootval, smp_processor_id(),
+                                      bootcpu);
+               return false;
+       }
+
+       ref = per_cpu_ptr(&tsc_adjust, refcpu);
+       /*
+        * Compare the boot value and complain if it differs in the
+        * package.
+        */
+       if (bootval != ref->bootval) {
+               pr_warn(FW_BUG "TSC ADJUST differs: Reference CPU%u: %lld CPU%u: %lld\n",
+                       refcpu, ref->bootval, cpu, bootval);
+       }
+       /*
+        * The TSC_ADJUST values in a package must be the same. If the boot
+        * value on this newly upcoming CPU differs from the adjustment
+        * value of the already online CPU in this package, set it to that
+        * adjusted value.
+        */
+       if (bootval != ref->adjusted) {
+               pr_warn("TSC ADJUST synchronize: Reference CPU%u: %lld CPU%u: %lld\n",
+                       refcpu, ref->adjusted, cpu, bootval);
+               cur->adjusted = ref->adjusted;
+               wrmsrl(MSR_IA32_TSC_ADJUST, ref->adjusted);
+       }
+       /*
+        * We have the TSCs forced to be in sync on this package. Skip sync
+        * test:
+        */
+       return true;
+}
+
 /*
  * Entry/exit counters that make sure that both CPUs
  * run the measurement code at once:
  */
 static atomic_t start_count;
 static atomic_t stop_count;
+static atomic_t skip_test;
+static atomic_t test_runs;
 
 /*
  * We use a raw spinlock in this exceptional case, because
@@ -37,15 +185,16 @@ static arch_spinlock_t sync_lock = __ARCH_SPIN_LOCK_UNLOCKED;
 static cycles_t last_tsc;
 static cycles_t max_warp;
 static int nr_warps;
+static int random_warps;
 
 /*
  * TSC-warp measurement loop running on both CPUs.  This is not called
  * if there is no TSC.
  */
-static void check_tsc_warp(unsigned int timeout)
+static cycles_t check_tsc_warp(unsigned int timeout)
 {
-       cycles_t start, now, prev, end;
-       int i;
+       cycles_t start, now, prev, end, cur_max_warp = 0;
+       int i, cur_warps = 0;
 
        start = rdtsc_ordered();
        /*
@@ -85,13 +234,22 @@ static void check_tsc_warp(unsigned int timeout)
                if (unlikely(prev > now)) {
                        arch_spin_lock(&sync_lock);
                        max_warp = max(max_warp, prev - now);
+                       cur_max_warp = max_warp;
+                       /*
+                        * Check whether this bounces back and forth. Only
+                        * one CPU should observe time going backwards.
+                        */
+                       if (cur_warps != nr_warps)
+                               random_warps++;
                        nr_warps++;
+                       cur_warps = nr_warps;
                        arch_spin_unlock(&sync_lock);
                }
        }
        WARN(!(now-start),
                "Warning: zero tsc calibration delta: %Ld [max: %Ld]\n",
                        now-start, end-start);
+       return cur_max_warp;
 }
 
 /*
@@ -136,15 +294,26 @@ void check_tsc_sync_source(int cpu)
        }
 
        /*
-        * Reset it - in case this is a second bootup:
+        * Set the maximum number of test runs to
+        *  1 if the CPU does not provide the TSC_ADJUST MSR
+        *  3 if the MSR is available, so the target can try to adjust
         */
-       atomic_set(&stop_count, 0);
-
+       if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+               atomic_set(&test_runs, 1);
+       else
+               atomic_set(&test_runs, 3);
+retry:
        /*
-        * Wait for the target to arrive:
+        * Wait for the target to start or to skip the test:
         */
-       while (atomic_read(&start_count) != cpus-1)
+       while (atomic_read(&start_count) != cpus - 1) {
+               if (atomic_read(&skip_test) > 0) {
+                       atomic_set(&skip_test, 0);
+                       return;
+               }
                cpu_relax();
+       }
+
        /*
         * Trigger the target to continue into the measurement too:
         */
@@ -155,21 +324,35 @@ void check_tsc_sync_source(int cpu)
        while (atomic_read(&stop_count) != cpus-1)
                cpu_relax();
 
-       if (nr_warps) {
+       /*
+        * If the test was successful set the number of runs to zero and
+        * stop. If not, decrement the number of runs an check if we can
+        * retry. In case of random warps no retry is attempted.
+        */
+       if (!nr_warps) {
+               atomic_set(&test_runs, 0);
+
+               pr_debug("TSC synchronization [CPU#%d -> CPU#%d]: passed\n",
+                       smp_processor_id(), cpu);
+
+       } else if (atomic_dec_and_test(&test_runs) || random_warps) {
+               /* Force it to 0 if random warps brought us here */
+               atomic_set(&test_runs, 0);
+
                pr_warning("TSC synchronization [CPU#%d -> CPU#%d]:\n",
                        smp_processor_id(), cpu);
                pr_warning("Measured %Ld cycles TSC warp between CPUs, "
                           "turning off TSC clock.\n", max_warp);
+               if (random_warps)
+                       pr_warning("TSC warped randomly between CPUs\n");
                mark_tsc_unstable("check_tsc_sync_source failed");
-       } else {
-               pr_debug("TSC synchronization [CPU#%d -> CPU#%d]: passed\n",
-                       smp_processor_id(), cpu);
        }
 
        /*
         * Reset it - just in case we boot another CPU later:
         */
        atomic_set(&start_count, 0);
+       random_warps = 0;
        nr_warps = 0;
        max_warp = 0;
        last_tsc = 0;
@@ -178,6 +361,12 @@ void check_tsc_sync_source(int cpu)
         * Let the target continue with the bootup:
         */
        atomic_inc(&stop_count);
+
+       /*
+        * Retry, if there is a chance to do so.
+        */
+       if (atomic_read(&test_runs) > 0)
+               goto retry;
 }
 
 /*
@@ -185,12 +374,25 @@ void check_tsc_sync_source(int cpu)
  */
 void check_tsc_sync_target(void)
 {
+       struct tsc_adjust *cur = this_cpu_ptr(&tsc_adjust);
+       unsigned int cpu = smp_processor_id();
+       cycles_t cur_max_warp, gbl_max_warp;
        int cpus = 2;
 
        /* Also aborts if there is no TSC. */
        if (unsynchronized_tsc() || tsc_clocksource_reliable)
                return;
 
+       /*
+        * Store, verify and sanitize the TSC adjust register. If
+        * successful skip the test.
+        */
+       if (tsc_store_and_check_tsc_adjust(false)) {
+               atomic_inc(&skip_test);
+               return;
+       }
+
+retry:
        /*
         * Register this CPU's participation and wait for the
         * source CPU to start the measurement:
@@ -199,7 +401,12 @@ void check_tsc_sync_target(void)
        while (atomic_read(&start_count) != cpus)
                cpu_relax();
 
-       check_tsc_warp(loop_timeout(smp_processor_id()));
+       cur_max_warp = check_tsc_warp(loop_timeout(cpu));
+
+       /*
+        * Store the maximum observed warp value for a potential retry:
+        */
+       gbl_max_warp = max_warp;
 
        /*
         * Ok, we are done:
@@ -211,4 +418,61 @@ void check_tsc_sync_target(void)
         */
        while (atomic_read(&stop_count) != cpus)
                cpu_relax();
+
+       /*
+        * Reset it for the next sync test:
+        */
+       atomic_set(&stop_count, 0);
+
+       /*
+        * Check the number of remaining test runs. If not zero, the test
+        * failed and a retry with adjusted TSC is possible. If zero the
+        * test was either successful or failed terminally.
+        */
+       if (!atomic_read(&test_runs))
+               return;
+
+       /*
+        * If the warp value of this CPU is 0, then the other CPU
+        * observed time going backwards so this TSC was ahead and
+        * needs to move backwards.
+        */
+       if (!cur_max_warp)
+               cur_max_warp = -gbl_max_warp;
+
+       /*
+        * Add the result to the previous adjustment value.
+        *
+        * The adjustement value is slightly off by the overhead of the
+        * sync mechanism (observed values are ~200 TSC cycles), but this
+        * really depends on CPU, node distance and frequency. So
+        * compensating for this is hard to get right. Experiments show
+        * that the warp is not longer detectable when the observed warp
+        * value is used. In the worst case the adjustment needs to go
+        * through a 3rd run for fine tuning.
+        */
+       cur->adjusted += cur_max_warp;
+
+       /*
+        * TSC deadline timer stops working or creates an interrupt storm
+        * with adjust values < 0 and > x07ffffff.
+        *
+        * To allow adjust values > 0x7FFFFFFF we need to disable the
+        * deadline timer and use the local APIC timer, but that requires
+        * more intrusive changes and we do not have any useful information
+        * from Intel about the underlying HW wreckage yet.
+        */
+       if (cur->adjusted < 0)
+               cur->adjusted = 0;
+       if (cur->adjusted > 0x7FFFFFFF)
+               cur->adjusted = 0x7FFFFFFF;
+
+       pr_warn("TSC ADJUST compensate: CPU%u observed %lld warp. Adjust: %lld\n",
+               cpu, cur_max_warp, cur->adjusted);
+
+       wrmsrl(MSR_IA32_TSC_ADJUST, cur->adjusted);
+       goto retry;
+
 }
+
+#endif /* CONFIG_SMP */
index b2d3cf1ef54ae5c1cc0bfb19c8c65b08dd6f23b4..e85f6bd7b9d526266ca5f11cfd9a23f7ce19337d 100644 (file)
@@ -373,16 +373,17 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        const u32 kvm_cpuid_7_0_ebx_x86_features =
                F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
                F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
-               F(ADX) | F(SMAP) | F(AVX512F) | F(AVX512PF) | F(AVX512ER) |
-               F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
-               F(AVX512BW) | F(AVX512VL);
+               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
+               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
+               F(SHA_NI) | F(AVX512BW) | F(AVX512VL);
 
        /* cpuid 0xD.1.eax */
        const u32 kvm_cpuid_D_1_eax_x86_features =
                F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | f_xsaves;
 
        /* cpuid 7.0.ecx*/
-       const u32 kvm_cpuid_7_0_ecx_x86_features = F(PKU) | 0 /*OSPKE*/;
+       const u32 kvm_cpuid_7_0_ecx_x86_features =
+               F(AVX512VBMI) | F(PKU) | 0 /*OSPKE*/;
 
        /* cpuid 7.0.edx*/
        const u32 kvm_cpuid_7_0_edx_x86_features =
index 99cde5220e0799fd84aca5a6774dce47e289a73c..1572c35b4f1a637b2ebb622ae88c5e7e14eafd63 100644 (file)
@@ -852,6 +852,10 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
                return;
 
+       mutex_lock(&kvm->arch.hyperv.hv_lock);
+       if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
+               goto out_unlock;
+
        gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
        /*
         * Because the TSC parameters only vary when there is a
@@ -859,7 +863,7 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
         */
        if (unlikely(kvm_read_guest(kvm, gfn_to_gpa(gfn),
                                    &tsc_seq, sizeof(tsc_seq))))
-               return;
+               goto out_unlock;
 
        /*
         * While we're computing and writing the parameters, force the
@@ -868,15 +872,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        hv->tsc_ref.tsc_sequence = 0;
        if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
                            &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
-               return;
+               goto out_unlock;
 
        if (!compute_tsc_page_parameters(hv_clock, &hv->tsc_ref))
-               return;
+               goto out_unlock;
 
        /* Ensure sequence is zero before writing the rest of the struct.  */
        smp_wmb();
        if (kvm_write_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref)))
-               return;
+               goto out_unlock;
 
        /*
         * Now switch to the TSC page mechanism by writing the sequence.
@@ -891,6 +895,8 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        hv->tsc_ref.tsc_sequence = tsc_seq;
        kvm_write_guest(kvm, gfn_to_gpa(gfn),
                        &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence));
+out_unlock:
+       mutex_unlock(&kvm->arch.hyperv.hv_lock);
 }
 
 static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
@@ -1142,9 +1148,9 @@ int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
        if (kvm_hv_msr_partition_wide(msr)) {
                int r;
 
-               mutex_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock);
                r = kvm_hv_set_msr_pw(vcpu, msr, data, host);
-               mutex_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock);
                return r;
        } else
                return kvm_hv_set_msr(vcpu, msr, data, host);
@@ -1155,9 +1161,9 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
        if (kvm_hv_msr_partition_wide(msr)) {
                int r;
 
-               mutex_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock);
                r = kvm_hv_get_msr_pw(vcpu, msr, pdata);
-               mutex_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock);
                return r;
        } else
                return kvm_hv_get_msr(vcpu, msr, pdata);
@@ -1165,7 +1171,7 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 
 bool kvm_hv_hypercall_enabled(struct kvm *kvm)
 {
-       return kvm->arch.hyperv.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE;
+       return READ_ONCE(kvm->arch.hyperv.hv_hypercall) & HV_X64_MSR_HYPERCALL_ENABLE;
 }
 
 static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
index aae43c6f24721e748451aea69d9c138c4be58f61..24db5fb6f575af27d3b61a67b15ce9996158ed8b 100644 (file)
@@ -1389,10 +1389,10 @@ static inline bool nested_cpu_has_posted_intr(struct vmcs12 *vmcs12)
        return vmcs12->pin_based_vm_exec_control & PIN_BASED_POSTED_INTR;
 }
 
-static inline bool is_exception(u32 intr_info)
+static inline bool is_nmi(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
-               == (INTR_TYPE_HARD_EXCEPTION | INTR_INFO_VALID_MASK);
+               == (INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK);
 }
 
 static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
@@ -5728,7 +5728,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
        if (is_machine_check(intr_info))
                return handle_machine_check(vcpu);
 
-       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
+       if (is_nmi(intr_info))
                return 1;  /* already handled by vmx_vcpu_run() */
 
        if (is_no_device(intr_info)) {
@@ -7122,7 +7122,7 @@ static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason,
 
                if (vmptr == vmx->nested.vmxon_ptr) {
                        nested_vmx_failValid(vcpu,
-                                            VMXERR_VMCLEAR_VMXON_POINTER);
+                                            VMXERR_VMPTRLD_VMXON_POINTER);
                        return kvm_skip_emulated_instruction(vcpu);
                }
                break;
@@ -8170,7 +8170,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
 
        switch (exit_reason) {
        case EXIT_REASON_EXCEPTION_NMI:
-               if (!is_exception(intr_info))
+               if (is_nmi(intr_info))
                        return false;
                else if (is_page_fault(intr_info))
                        return enable_ept;
@@ -8765,8 +8765,7 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
                kvm_machine_check();
 
        /* We need to handle NMIs before interrupts are enabled */
-       if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
-           (exit_intr_info & INTR_INFO_VALID_MASK)) {
+       if (is_nmi(exit_intr_info)) {
                kvm_before_handle_nmi(&vmx->vcpu);
                asm("int $2");
                kvm_after_handle_nmi(&vmx->vcpu);
index 1f0d2383f5ee6e273751949a77882224947a7861..445c51b6cf6dc702a0da9710ee5b6eb4b996ec34 100644 (file)
@@ -2844,7 +2844,24 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+       int idx;
+       /*
+        * Disable page faults because we're in atomic context here.
+        * kvm_write_guest_offset_cached() would call might_fault()
+        * that relies on pagefault_disable() to tell if there's a
+        * bug. NOTE: the write to guest memory may not go through if
+        * during postcopy live migration or if there's heavy guest
+        * paging.
+        */
+       pagefault_disable();
+       /*
+        * kvm_memslots() will be called by
+        * kvm_write_guest_offset_cached() so take the srcu lock.
+        */
+       idx = srcu_read_lock(&vcpu->kvm->srcu);
        kvm_steal_time_set_preempted(vcpu);
+       srcu_read_unlock(&vcpu->kvm->srcu, idx);
+       pagefault_enable();
        kvm_x86_ops->vcpu_put(vcpu);
        kvm_put_guest_fpu(vcpu);
        vcpu->arch.last_host_tsc = rdtsc();
@@ -7881,6 +7898,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        raw_spin_lock_init(&kvm->arch.tsc_write_lock);
        mutex_init(&kvm->arch.apic_map_lock);
+       mutex_init(&kvm->arch.hyperv.hv_lock);
        spin_lock_init(&kvm->arch.pvclock_gtod_sync_lock);
 
        kvm->arch.kvmclock_offset = -ktime_get_boot_ns();
index 17c55a536fdd2ce1af8b376a319e43cea3e7d45a..e3254ca0eec4ec371d6498dcb72f140ac2164a77 100644 (file)
@@ -413,7 +413,7 @@ out:
 
 void vmalloc_sync_all(void)
 {
-       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END, 0);
+       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END);
 }
 
 /*
index 14b9dd71d9e864e218b28f82c95df8f011cc0c91..963895f9af7fb8d7feba7ccfba05a08bcec30f2d 100644 (file)
@@ -89,10 +89,10 @@ static int __init nonx32_setup(char *str)
 __setup("noexec32=", nonx32_setup);
 
 /*
- * When memory was added/removed make sure all the processes MM have
+ * When memory was added make sure all the processes MM have
  * suitable PGD entries in the local PGD level page.
  */
-void sync_global_pgds(unsigned long start, unsigned long end, int removed)
+void sync_global_pgds(unsigned long start, unsigned long end)
 {
        unsigned long address;
 
@@ -100,12 +100,7 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed)
                const pgd_t *pgd_ref = pgd_offset_k(address);
                struct page *page;
 
-               /*
-                * When it is called after memory hot remove, pgd_none()
-                * returns true. In this case (removed == 1), we must clear
-                * the PGD entries in the local PGD level page.
-                */
-               if (pgd_none(*pgd_ref) && !removed)
+               if (pgd_none(*pgd_ref))
                        continue;
 
                spin_lock(&pgd_lock);
@@ -122,13 +117,8 @@ void sync_global_pgds(unsigned long start, unsigned long end, int removed)
                                BUG_ON(pgd_page_vaddr(*pgd)
                                       != pgd_page_vaddr(*pgd_ref));
 
-                       if (removed) {
-                               if (pgd_none(*pgd_ref) && !pgd_none(*pgd))
-                                       pgd_clear(pgd);
-                       } else {
-                               if (pgd_none(*pgd))
-                                       set_pgd(pgd, *pgd_ref);
-                       }
+                       if (pgd_none(*pgd))
+                               set_pgd(pgd, *pgd_ref);
 
                        spin_unlock(pgt_lock);
                }
@@ -596,7 +586,7 @@ kernel_physical_mapping_init(unsigned long paddr_start,
        }
 
        if (pgd_changed)
-               sync_global_pgds(vaddr_start, vaddr_end - 1, 0);
+               sync_global_pgds(vaddr_start, vaddr_end - 1);
 
        __flush_tlb_all();
 
@@ -1239,7 +1229,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
        } else
                err = vmemmap_populate_basepages(start, end, node);
        if (!err)
-               sync_global_pgds(start, end - 1, 0);
+               sync_global_pgds(start, end - 1);
        return err;
 }
 
index e4f800999b32dc94d5ba1a1283591649a818fbb7..324e5713d386f0ed235b0394f71c0290df870fae 100644 (file)
@@ -350,12 +350,12 @@ int mpx_enable_management(void)
         * The copy_xregs_to_kernel() beneath get_xsave_field_ptr() is
         * expected to be relatively expensive. Storing the bounds
         * directory here means that we do not have to do xsave in the
-        * unmap path; we can just use mm->bd_addr instead.
+        * unmap path; we can just use mm->context.bd_addr instead.
         */
        bd_base = mpx_get_bounds_dir();
        down_write(&mm->mmap_sem);
-       mm->bd_addr = bd_base;
-       if (mm->bd_addr == MPX_INVALID_BOUNDS_DIR)
+       mm->context.bd_addr = bd_base;
+       if (mm->context.bd_addr == MPX_INVALID_BOUNDS_DIR)
                ret = -ENXIO;
 
        up_write(&mm->mmap_sem);
@@ -370,7 +370,7 @@ int mpx_disable_management(void)
                return -ENXIO;
 
        down_write(&mm->mmap_sem);
-       mm->bd_addr = MPX_INVALID_BOUNDS_DIR;
+       mm->context.bd_addr = MPX_INVALID_BOUNDS_DIR;
        up_write(&mm->mmap_sem);
        return 0;
 }
@@ -947,7 +947,7 @@ static int try_unmap_single_bt(struct mm_struct *mm,
                end = bta_end_vaddr;
        }
 
-       bde_vaddr = mm->bd_addr + mpx_get_bd_entry_offset(mm, start);
+       bde_vaddr = mm->context.bd_addr + mpx_get_bd_entry_offset(mm, start);
        ret = get_bt_addr(mm, bde_vaddr, &bt_addr);
        /*
         * No bounds table there, so nothing to unmap.
index 3f35b48d1d9de6dcef0f6a24a9a0ed377e4b8889..12dcad7297a5b70ac34a7a1ca7711aca13e9d9cc 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "numa_internal.h"
 
-int __initdata numa_off;
+int numa_off;
 nodemask_t numa_nodes_parsed __initdata;
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
index 3c3c19ea94df460b061e232f17cd35fd144eeef6..184842ef332e0123762c3463bd795ef4a9aaa282 100644 (file)
@@ -8,7 +8,6 @@ obj-y   += iris/
 obj-y  += intel/
 obj-y  += intel-mid/
 obj-y  += intel-quark/
-obj-y  += mellanox/
 obj-y  += olpc/
 obj-y  += scx200/
 obj-y  += sfi/
index 1eb47b6298c20fc20ae6de0c2f9f3762854286cc..e793fe509971f49fb2cfa6a12f8b365a937ae206 100644 (file)
@@ -49,8 +49,13 @@ static unsigned long __init mfld_calibrate_tsc(void)
        fast_calibrate = ratio * fsb;
        pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
        lapic_timer_frequency = fsb * 1000 / HZ;
-       /* mark tsc clocksource as reliable */
-       set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
+
+       /*
+        * TSC on Intel Atom SoCs is reliable and of known frequency.
+        * See tsc_msr.c for details.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+       setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
 
        return fast_calibrate;
 }
index 59253db41bbc900d238e361b9fce339161be1753..e0607c77a1bd67a06fe49f58c50c1bfe9af9da61 100644 (file)
@@ -78,8 +78,12 @@ static unsigned long __init tangier_calibrate_tsc(void)
        pr_debug("Setting lapic_timer_frequency = %d\n",
                        lapic_timer_frequency);
 
-       /* mark tsc clocksource as reliable */
-       set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
+       /*
+        * TSC on Intel Atom SoCs is reliable and of known frequency.
+        * See tsc_msr.c for details.
+        */
+       setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+       setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
 
        return fast_calibrate;
 }
diff --git a/arch/x86/platform/mellanox/Makefile b/arch/x86/platform/mellanox/Makefile
deleted file mode 100644 (file)
index f43c931..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_MLX_PLATFORM)     += mlx-platform.o
diff --git a/arch/x86/platform/mellanox/mlx-platform.c b/arch/x86/platform/mellanox/mlx-platform.c
deleted file mode 100644 (file)
index 7dcfcca..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * arch/x86/platform/mellanox/mlx-platform.c
- * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/device.h>
-#include <linux/dmi.h>
-#include <linux/i2c.h>
-#include <linux/i2c-mux.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/i2c-mux-reg.h>
-
-#define MLX_PLAT_DEVICE_NAME           "mlxplat"
-
-/* LPC bus IO offsets */
-#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR         0x2000
-#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
-#define MLXPLAT_CPLD_LPC_IO_RANGE              0x100
-#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF           0xdb
-#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF           0xda
-#define MLXPLAT_CPLD_LPC_PIO_OFFSET            0x10000UL
-#define MLXPLAT_CPLD_LPC_REG1  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
-                                 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
-                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
-#define MLXPLAT_CPLD_LPC_REG2  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
-                                 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
-                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
-
-/* Start channel numbers */
-#define MLXPLAT_CPLD_CH1                       2
-#define MLXPLAT_CPLD_CH2                       10
-
-/* Number of LPC attached MUX platform devices */
-#define MLXPLAT_CPLD_LPC_MUX_DEVS              2
-
-/* mlxplat_priv - platform private data
- * @pdev_i2c - i2c controller platform device
- * @pdev_mux - array of mux platform devices
- */
-struct mlxplat_priv {
-       struct platform_device *pdev_i2c;
-       struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
-};
-
-/* Regions for LPC I2C controller and LPC base register space */
-static const struct resource mlxplat_lpc_resources[] = {
-       [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
-                              MLXPLAT_CPLD_LPC_IO_RANGE,
-                              "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
-       [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
-                              MLXPLAT_CPLD_LPC_IO_RANGE,
-                              "mlxplat_cpld_lpc_regs",
-                              IORESOURCE_IO),
-};
-
-/* Platform default channels */
-static const int mlxplat_default_channels[][8] = {
-       {
-               MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
-               MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
-               5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
-       },
-       {
-               MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
-               MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
-               5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
-       },
-};
-
-/* Platform channels for MSN21xx system family */
-static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
-
-/* Platform mux data */
-static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
-       {
-               .parent = 1,
-               .base_nr = MLXPLAT_CPLD_CH1,
-               .write_only = 1,
-               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
-               .reg_size = 1,
-               .idle_in_use = 1,
-       },
-       {
-               .parent = 1,
-               .base_nr = MLXPLAT_CPLD_CH2,
-               .write_only = 1,
-               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
-               .reg_size = 1,
-               .idle_in_use = 1,
-       },
-
-};
-
-static struct platform_device *mlxplat_dev;
-
-static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
-               mlxplat_mux_data[i].values = mlxplat_default_channels[i];
-               mlxplat_mux_data[i].n_values =
-                               ARRAY_SIZE(mlxplat_default_channels[i]);
-       }
-
-       return 1;
-};
-
-static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
-               mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
-               mlxplat_mux_data[i].n_values =
-                               ARRAY_SIZE(mlxplat_msn21xx_channels);
-       }
-
-       return 1;
-};
-
-static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_default_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
-               },
-       },
-       {
-               .callback = mlxplat_dmi_msn21xx_matched,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
-               },
-       },
-       { }
-};
-
-static int __init mlxplat_init(void)
-{
-       struct mlxplat_priv *priv;
-       int i, err;
-
-       if (!dmi_check_system(mlxplat_dmi_table))
-               return -ENODEV;
-
-       mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
-                                       mlxplat_lpc_resources,
-                                       ARRAY_SIZE(mlxplat_lpc_resources));
-
-       if (IS_ERR(mlxplat_dev))
-               return PTR_ERR(mlxplat_dev);
-
-       priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
-                           GFP_KERNEL);
-       if (!priv) {
-               err = -ENOMEM;
-               goto fail_alloc;
-       }
-       platform_set_drvdata(mlxplat_dev, priv);
-
-       priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
-                                                        NULL, 0);
-       if (IS_ERR(priv->pdev_i2c)) {
-               err = PTR_ERR(priv->pdev_i2c);
-               goto fail_alloc;
-       };
-
-       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
-               priv->pdev_mux[i] = platform_device_register_resndata(
-                                               &mlxplat_dev->dev,
-                                               "i2c-mux-reg", i, NULL,
-                                               0, &mlxplat_mux_data[i],
-                                               sizeof(mlxplat_mux_data[i]));
-               if (IS_ERR(priv->pdev_mux[i])) {
-                       err = PTR_ERR(priv->pdev_mux[i]);
-                       goto fail_platform_mux_register;
-               }
-       }
-
-       return 0;
-
-fail_platform_mux_register:
-       for (i--; i > 0 ; i--)
-               platform_device_unregister(priv->pdev_mux[i]);
-       platform_device_unregister(priv->pdev_i2c);
-fail_alloc:
-       platform_device_unregister(mlxplat_dev);
-
-       return err;
-}
-module_init(mlxplat_init);
-
-static void __exit mlxplat_exit(void)
-{
-       struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
-       int i;
-
-       for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
-               platform_device_unregister(priv->pdev_mux[i]);
-
-       platform_device_unregister(priv->pdev_i2c);
-       platform_device_unregister(mlxplat_dev);
-}
-module_exit(mlxplat_exit);
-
-MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
-MODULE_DESCRIPTION("Mellanox platform driver");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
index 53cace2ec0e2888baa5937edce817d00bd09de64..66ade16c769363ecd1bef435eccfd4977ffd5228 100644 (file)
@@ -252,6 +252,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
        fix_processor_context();
 
        do_fpu_end();
+       tsc_verify_tsc_adjust(true);
        x86_platform.restore_sched_clock_state();
        mtrr_bp_restore();
        perf_restore_debug_store();
index 9fa27ceeecfdaea1cfdbba751e79b405d857d851..311acad7dad2abdc8501c70866674ed4f5858495 100644 (file)
@@ -87,12 +87,6 @@ static void cpu_bringup(void)
        cpu_data(cpu).x86_max_cores = 1;
        set_cpu_sibling_map(cpu);
 
-       /*
-        * identify_cpu() may have set logical_pkg_id to -1 due
-        * to incorrect phys_proc_id. Let's re-comupte it.
-        */
-       topology_update_package_map(apic->cpu_present_to_apicid(cpu), cpu);
-
        xen_setup_cpu_clockevents();
 
        notify_cpu_starting(cpu);
index f61058617ada462c6e571c7936c3ebf92621aa26..f4126cf997a469da01161244e93a320d1dd2104e 100644 (file)
@@ -15,6 +15,7 @@ config XTENSA
        select GENERIC_SCHED_CLOCK
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_API_DEBUG
+       select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUTEX_CMPXCHG if !MMU
index b1f4ee8c9a22371ba9abedfcc7d21fb279b585f0..6106bdc097ad2f51a257d7643770b89c8d82ab8e 100644 (file)
                device_type = "memory";
                reg = <0x00000000 0x38000000>;
        };
+
+       reserved-memory {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               /* global autoconfigured region for contiguous allocations */
+               linux,cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0x04000000>;
+                       alignment = <0x2000>;
+                       alloc-ranges = <0x00000000 0x20000000>;
+                       linux,cma-default;
+               };
+       };
 };
index 28cf4c5d65efade019dbefaf809e71d13624e37c..b7fbaa56b51a573f393ce6d6abb6ec5c1895c27e 100644 (file)
@@ -3,6 +3,7 @@ generic-y += bug.h
 generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += div64.h
+generic-y += dma-contiguous.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
index c31f5d5afc7d2d969a2a0c532e9f91a4395ba49d..264fb89c444e9fde9fd5ba9157aba6d7b06eae2f 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
 obj-$(CONFIG_SMP) += smp.o mxhead.o
 obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
+obj-$(CONFIG_S32C1I_SELFTEST) += s32c1i_selftest.o
 
 AFLAGS_head.o += -mtext-section-literals
 AFLAGS_mxhead.o += -mtext-section-literals
index 6a16decf278fa0a7dfa4dd5200e55a31258dace3..70e362e6038e80c0e802bf6f2a1ebb3360292c07 100644 (file)
@@ -15,6 +15,7 @@
  * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
  */
 
+#include <linux/dma-contiguous.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
@@ -146,6 +147,8 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 {
        unsigned long ret;
        unsigned long uncached = 0;
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page *page = NULL;
 
        /* ignore region speicifiers */
 
@@ -153,11 +156,18 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 
        if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
                flag |= GFP_DMA;
-       ret = (unsigned long)__get_free_pages(flag, get_order(size));
 
-       if (ret == 0)
+       if (gfpflags_allow_blocking(flag))
+               page = dma_alloc_from_contiguous(dev, count, get_order(size));
+
+       if (!page)
+               page = alloc_pages(flag, get_order(size));
+
+       if (!page)
                return NULL;
 
+       ret = (unsigned long)page_address(page);
+
        /* We currently don't support coherent memory outside KSEG */
 
        BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
@@ -170,16 +180,19 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
        return (void *)uncached;
 }
 
-static void xtensa_dma_free(struct device *hwdev, size_t size, void *vaddr,
+static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr,
                            dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long)vaddr +
                XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
+       struct page *page = virt_to_page(addr);
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
               addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
-       free_pages(addr, get_order(size));
+       if (!dma_release_from_contiguous(dev, page, count))
+               __free_pages(page, get_order(size));
 }
 
 static dma_addr_t xtensa_map_page(struct device *dev, struct page *page,
diff --git a/arch/xtensa/kernel/s32c1i_selftest.c b/arch/xtensa/kernel/s32c1i_selftest.c
new file mode 100644 (file)
index 0000000..07e56e3
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * S32C1I selftest.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2016 Cadence Design Systems Inc.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/traps.h>
+
+#if XCHAL_HAVE_S32C1I
+
+static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
+
+/*
+ * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
+ *
+ * If *v == cmp, set *v = set.  Return previous *v.
+ */
+static inline int probed_compare_swap(int *v, int cmp, int set)
+{
+       int tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %1, 1f\n"
+                       "       s32i    %1, %4, 0\n"
+                       "       wsr     %2, scompare1\n"
+                       "1:     s32c1i  %0, %3, 0\n"
+                       : "=a" (set), "=&a" (tmp)
+                       : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
+                       : "memory"
+                       );
+       return set;
+}
+
+/* Handle probed exception */
+
+static void __init do_probed_exception(struct pt_regs *regs,
+                                      unsigned long exccause)
+{
+       if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
+               regs->pc += 3;          /* skip the s32c1i instruction */
+               rcw_exc = exccause;
+       } else {
+               do_unhandled(regs, exccause);
+       }
+}
+
+/* Simple test of S32C1I (soc bringup assist) */
+
+static int __init check_s32c1i(void)
+{
+       int n, cause1, cause2;
+       void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
+
+       rcw_probe_pc = 0;
+       handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
+                       do_probed_exception);
+       handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
+                       do_probed_exception);
+       handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
+                       do_probed_exception);
+
+       /* First try an S32C1I that does not store: */
+       rcw_exc = 0;
+       rcw_word = 1;
+       n = probed_compare_swap(&rcw_word, 0, 2);
+       cause1 = rcw_exc;
+
+       /* took exception? */
+       if (cause1 != 0) {
+               /* unclean exception? */
+               if (n != 2 || rcw_word != 1)
+                       panic("S32C1I exception error");
+       } else if (rcw_word != 1 || n != 1) {
+               panic("S32C1I compare error");
+       }
+
+       /* Then an S32C1I that stores: */
+       rcw_exc = 0;
+       rcw_word = 0x1234567;
+       n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
+       cause2 = rcw_exc;
+
+       if (cause2 != 0) {
+               /* unclean exception? */
+               if (n != 0xabcde || rcw_word != 0x1234567)
+                       panic("S32C1I exception error (b)");
+       } else if (rcw_word != 0xabcde || n != 0x1234567) {
+               panic("S32C1I store error");
+       }
+
+       /* Verify consistency of exceptions: */
+       if (cause1 || cause2) {
+               pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
+               /* If emulation of S32C1I upon bus error gets implemented,
+                * we can get rid of this panic for single core (not SMP)
+                */
+               panic("S32C1I exceptions not currently supported");
+       }
+       if (cause1 != cause2)
+               panic("inconsistent S32C1I exceptions");
+
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
+       return 0;
+}
+
+#else /* XCHAL_HAVE_S32C1I */
+
+/* This condition should not occur with a commercially deployed processor.
+ * Display reminder for early engr test or demo chips / FPGA bitstreams
+ */
+static int __init check_s32c1i(void)
+{
+       pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
+       return 0;
+}
+
+#endif /* XCHAL_HAVE_S32C1I */
+
+early_initcall(check_s32c1i);
index 88a044af7504dd9c47d0f97d64620ac8de4b5739..848e8568fb3c4a90c2eb89783c0420f8b5526cd6 100644 (file)
 # include <linux/console.h>
 #endif
 
-#ifdef CONFIG_RTC
-# include <linux/timex.h>
-#endif
-
 #ifdef CONFIG_PROC_FS
 # include <linux/seq_file.h>
 #endif
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <asm/param.h>
-#include <asm/traps.h>
 #include <asm/smp.h>
 #include <asm/sysmem.h>
 
 #include <platform/hardware.h>
 
 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
-struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
-#endif
-
-#ifdef CONFIG_BLK_DEV_FD
-extern struct fd_ops no_fd_ops;
-struct fd_ops *fd_ops;
+struct screen_info screen_info = {
+       .orig_x = 0,
+       .orig_y = 24,
+       .orig_video_cols = 80,
+       .orig_video_lines = 24,
+       .orig_video_isVGA = 1,
+       .orig_video_points = 16,
+};
 #endif
 
-extern struct rtc_ops no_rtc_ops;
-struct rtc_ops *rtc_ops;
-
 #ifdef CONFIG_BLK_DEV_INITRD
 extern unsigned long initrd_start;
 extern unsigned long initrd_end;
@@ -77,7 +71,6 @@ extern int initrd_below_start_ok;
 void *dtb_start = __dtb_start;
 #endif
 
-unsigned char aux_device_present;
 extern unsigned long loops_per_jiffy;
 
 /* Command line specified as configuration option. */
@@ -317,120 +310,6 @@ extern char _SecondaryResetVector_text_start;
 extern char _SecondaryResetVector_text_end;
 #endif
 
-
-#ifdef CONFIG_S32C1I_SELFTEST
-#if XCHAL_HAVE_S32C1I
-
-static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
-
-/*
- * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
- *
- * If *v == cmp, set *v = set.  Return previous *v.
- */
-static inline int probed_compare_swap(int *v, int cmp, int set)
-{
-       int tmp;
-
-       __asm__ __volatile__(
-                       "       movi    %1, 1f\n"
-                       "       s32i    %1, %4, 0\n"
-                       "       wsr     %2, scompare1\n"
-                       "1:     s32c1i  %0, %3, 0\n"
-                       : "=a" (set), "=&a" (tmp)
-                       : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
-                       : "memory"
-                       );
-       return set;
-}
-
-/* Handle probed exception */
-
-static void __init do_probed_exception(struct pt_regs *regs,
-               unsigned long exccause)
-{
-       if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
-               regs->pc += 3;          /* skip the s32c1i instruction */
-               rcw_exc = exccause;
-       } else {
-               do_unhandled(regs, exccause);
-       }
-}
-
-/* Simple test of S32C1I (soc bringup assist) */
-
-static int __init check_s32c1i(void)
-{
-       int n, cause1, cause2;
-       void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
-
-       rcw_probe_pc = 0;
-       handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
-                       do_probed_exception);
-       handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
-                       do_probed_exception);
-       handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
-                       do_probed_exception);
-
-       /* First try an S32C1I that does not store: */
-       rcw_exc = 0;
-       rcw_word = 1;
-       n = probed_compare_swap(&rcw_word, 0, 2);
-       cause1 = rcw_exc;
-
-       /* took exception? */
-       if (cause1 != 0) {
-               /* unclean exception? */
-               if (n != 2 || rcw_word != 1)
-                       panic("S32C1I exception error");
-       } else if (rcw_word != 1 || n != 1) {
-               panic("S32C1I compare error");
-       }
-
-       /* Then an S32C1I that stores: */
-       rcw_exc = 0;
-       rcw_word = 0x1234567;
-       n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
-       cause2 = rcw_exc;
-
-       if (cause2 != 0) {
-               /* unclean exception? */
-               if (n != 0xabcde || rcw_word != 0x1234567)
-                       panic("S32C1I exception error (b)");
-       } else if (rcw_word != 0xabcde || n != 0x1234567) {
-               panic("S32C1I store error");
-       }
-
-       /* Verify consistency of exceptions: */
-       if (cause1 || cause2) {
-               pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
-               /* If emulation of S32C1I upon bus error gets implemented,
-                  we can get rid of this panic for single core (not SMP) */
-               panic("S32C1I exceptions not currently supported");
-       }
-       if (cause1 != cause2)
-               panic("inconsistent S32C1I exceptions");
-
-       trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
-       trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
-       trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
-       return 0;
-}
-
-#else /* XCHAL_HAVE_S32C1I */
-
-/* This condition should not occur with a commercially deployed processor.
-   Display reminder for early engr test or demo chips / FPGA bitstreams */
-static int __init check_s32c1i(void)
-{
-       pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
-       return 0;
-}
-
-#endif /* XCHAL_HAVE_S32C1I */
-early_initcall(check_s32c1i);
-#endif /* CONFIG_S32C1I_SELFTEST */
-
 static inline int mem_reserve(unsigned long start, unsigned long end)
 {
        return memblock_reserve(start, end - start);
index 80e4cfb2471ad5af6a99433d6e8af76e16865558..720fe4e8b49712db84e4e00d5fb938c9ecb4220e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/nodemask.h>
 #include <linux/mm.h>
 #include <linux/of_fdt.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/bootparam.h>
 #include <asm/page.h>
@@ -60,6 +61,7 @@ void __init bootmem_init(void)
        max_low_pfn = min(max_pfn, MAX_LOW_PFN);
 
        memblock_set_current_limit(PFN_PHYS(max_low_pfn));
+       dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
 
        memblock_dump_all();
 }
index ce3a7a16f03fcc8f8bff97ec137b03df2f7986f1..edb0c79f7c64eea8b4d3cdde4467a356c20a32f8 100644 (file)
@@ -70,7 +70,7 @@ int acpi_map_pxm_to_node(int pxm)
 {
        int node;
 
-       if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+       if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
                return NUMA_NO_NODE;
 
        node = pxm_to_node_map[pxm];
index 26ec39ddf21ffa4f58d09e62dda0fab90e46ae5f..ed758b74ddf0b74fe3fdbc84f8dde771aead4aca 100644 (file)
@@ -75,6 +75,73 @@ struct dax_dev {
        struct resource res[0];
 };
 
+static ssize_t id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dax_region *dax_region;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       dax_region = dev_get_drvdata(dev);
+       if (dax_region)
+               rc = sprintf(buf, "%d\n", dax_region->id);
+       device_unlock(dev);
+
+       return rc;
+}
+static DEVICE_ATTR_RO(id);
+
+static ssize_t region_size_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dax_region *dax_region;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       dax_region = dev_get_drvdata(dev);
+       if (dax_region)
+               rc = sprintf(buf, "%llu\n", (unsigned long long)
+                               resource_size(&dax_region->res));
+       device_unlock(dev);
+
+       return rc;
+}
+static struct device_attribute dev_attr_region_size = __ATTR(size, 0444,
+               region_size_show, NULL);
+
+static ssize_t align_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct dax_region *dax_region;
+       ssize_t rc = -ENXIO;
+
+       device_lock(dev);
+       dax_region = dev_get_drvdata(dev);
+       if (dax_region)
+               rc = sprintf(buf, "%u\n", dax_region->align);
+       device_unlock(dev);
+
+       return rc;
+}
+static DEVICE_ATTR_RO(align);
+
+static struct attribute *dax_region_attributes[] = {
+       &dev_attr_region_size.attr,
+       &dev_attr_align.attr,
+       &dev_attr_id.attr,
+       NULL,
+};
+
+static const struct attribute_group dax_region_attribute_group = {
+       .name = "dax_region",
+       .attrs = dax_region_attributes,
+};
+
+static const struct attribute_group *dax_region_attribute_groups[] = {
+       &dax_region_attribute_group,
+       NULL,
+};
+
 static struct inode *dax_alloc_inode(struct super_block *sb)
 {
        return kmem_cache_alloc(dax_cache, GFP_KERNEL);
@@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region)
 }
 EXPORT_SYMBOL_GPL(dax_region_put);
 
+static void dax_region_unregister(void *region)
+{
+       struct dax_region *dax_region = region;
+
+       sysfs_remove_groups(&dax_region->dev->kobj,
+                       dax_region_attribute_groups);
+       dax_region_put(dax_region);
+}
+
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
                struct resource *res, unsigned int align, void *addr,
                unsigned long pfn_flags)
 {
        struct dax_region *dax_region;
 
+       /*
+        * The DAX core assumes that it can store its private data in
+        * parent->driver_data. This WARN is a reminder / safeguard for
+        * developers of device-dax drivers.
+        */
+       if (dev_get_drvdata(parent)) {
+               dev_WARN(parent, "dax core failed to setup private data\n");
+               return NULL;
+       }
+
        if (!IS_ALIGNED(res->start, align)
                        || !IS_ALIGNED(resource_size(res), align))
                return NULL;
@@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
        if (!dax_region)
                return NULL;
 
+       dev_set_drvdata(parent, dax_region);
        memcpy(&dax_region->res, res, sizeof(*res));
        dax_region->pfn_flags = pfn_flags;
        kref_init(&dax_region->kref);
@@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
        dax_region->align = align;
        dax_region->dev = parent;
        dax_region->base = addr;
+       if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) {
+               kfree(dax_region);
+               return NULL;;
+       }
 
+       kref_get(&dax_region->kref);
+       if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region))
+               return NULL;
        return dax_region;
 }
 EXPORT_SYMBOL_GPL(alloc_dax_region);
index 73c6ce93a0d9204227818465a707db9f7d5806fb..033f49b31fdcfeeedede6a6349bbdab5115c82f6 100644 (file)
@@ -89,7 +89,8 @@ static int dax_pmem_probe(struct device *dev)
        pfn_sb = nd_pfn->pfn_sb;
 
        if (!devm_request_mem_region(dev, nsio->res.start,
-                               resource_size(&nsio->res), dev_name(dev))) {
+                               resource_size(&nsio->res),
+                               dev_name(&ndns->dev))) {
                dev_warn(dev, "could not reserve region %pR\n", &nsio->res);
                return -EBUSY;
        }
index 88bebe1968b717b4060a449ff49278cee2a84315..54be60ead08f8068c18dc9bbfd5a40e3cb26685c 100644 (file)
@@ -560,7 +560,7 @@ static int __init dmi_present(const u8 *buf)
                                        dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
                        }
                        dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
-                       printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
+                       pr_info("DMI: %s\n", dmi_ids_string);
                        return 0;
                }
        }
@@ -588,7 +588,7 @@ static int __init dmi_smbios3_present(const u8 *buf)
                                dmi_ver >> 16, (dmi_ver >> 8) & 0xFF,
                                dmi_ver & 0xFF);
                        dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
-                       pr_debug("DMI: %s\n", dmi_ids_string);
+                       pr_info("DMI: %s\n", dmi_ids_string);
                        return 0;
                }
        }
index d779307a96852b15f251c9595e035e0ee537db7e..46e6dcc089cbdd25fdf61025c53e7dc078233de3 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65218.h>
 
 struct tps65218_gpio {
@@ -30,7 +31,7 @@ static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset)
        unsigned int val;
        int ret;
 
-       ret = tps65218_reg_read(tps65218, TPS65218_REG_ENABLE2, &val);
+       ret = regmap_read(tps65218->regmap, TPS65218_REG_ENABLE2, &val);
        if (ret)
                return ret;
 
index 08153ea4d848097ef5659f40c6bb71964cbc99e2..6ce4313231257f8251b62e02f5aaa390a4619edf 100644 (file)
@@ -150,6 +150,29 @@ static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
        return 0;
 }
 
+static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
+{
+       u32 param, tx_fifo_depth, rx_fifo_depth;
+
+       /*
+        * Try to detect the FIFO depth if not set by interface driver,
+        * the depth could be from 2 to 256 from HW spec.
+        */
+       param = i2c_dw_read_comp_param(dev);
+       tx_fifo_depth = ((param >> 16) & 0xff) + 1;
+       rx_fifo_depth = ((param >> 8)  & 0xff) + 1;
+       if (!dev->tx_fifo_depth) {
+               dev->tx_fifo_depth = tx_fifo_depth;
+               dev->rx_fifo_depth = rx_fifo_depth;
+               dev->adapter.nr = id;
+       } else if (tx_fifo_depth >= 2) {
+               dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth,
+                               tx_fifo_depth);
+               dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
+                               rx_fifo_depth);
+       }
+}
+
 static int dw_i2c_plat_probe(struct platform_device *pdev)
 {
        struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -245,13 +268,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
                                1000000);
        }
 
-       if (!dev->tx_fifo_depth) {
-               u32 param1 = i2c_dw_read_comp_param(dev);
-
-               dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
-               dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
-               dev->adapter.nr = pdev->id;
-       }
+       dw_i2c_set_fifo_size(dev, pdev->id);
 
        adap = &dev->adapter;
        adap->owner = THIS_MODULE;
index 3d10f1a802be4b8df5488535fda6e32f5d2b2fca..1d87757990568c40b9cebe4df7dda54fe21918f7 100644 (file)
@@ -342,7 +342,9 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
                if (result)
                        return result;
 
-               data[i] = octeon_i2c_data_read(i2c);
+               data[i] = octeon_i2c_data_read(i2c, &result);
+               if (result)
+                       return result;
                if (recv_len && i == 0) {
                        if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
                                return -EPROTO;
index 87151ea74acd475a37726fd43fa927f486ddc76e..e160f838c25461f111f89871eac87beebca61a09 100644 (file)
@@ -141,11 +141,14 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
  */
 static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
 {
+       int tries = 1000;
        u64 tmp;
 
        __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
        do {
                tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+               if (--tries < 0)
+                       return;
        } while ((tmp & SW_TWSI_V) != 0);
 }
 
@@ -163,24 +166,32 @@ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static inline u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
+static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
+                                     int *error)
 {
+       int tries = 1000;
        u64 tmp;
 
        __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
        do {
                tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+               if (--tries < 0) {
+                       /* signal that the returned data is invalid */
+                       if (error)
+                               *error = -EIO;
+                       return 0;
+               }
        } while ((tmp & SW_TWSI_V) != 0);
 
        return tmp & 0xFF;
 }
 
 #define octeon_i2c_ctl_read(i2c)                                       \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
-#define octeon_i2c_data_read(i2c)                                      \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
+#define octeon_i2c_data_read(i2c, error)                               \
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
 #define octeon_i2c_stat_read(i2c)                                      \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
 
 /**
  * octeon_i2c_read_int - read the TWSI_INT register
index 05cf192ef1acae340397d9ff67f942bca6d08d3e..0ab1e55558bcd7a520afd8dcf07ae3d8cb77e1c0 100644 (file)
@@ -415,6 +415,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
        adapter->algo = &xgene_slimpro_i2c_algorithm;
        adapter->class = I2C_CLASS_HWMON;
        adapter->dev.parent = &pdev->dev;
+       adapter->dev.of_node = pdev->dev.of_node;
        i2c_set_adapdata(adapter, ctx);
        rc = i2c_add_adapter(adapter);
        if (rc) {
index 3ab654bbfab56f4fe299800e2372fbee86b1385d..b7ca249ec9c38b884ed48fbb8387dcc6729f1cc6 100644 (file)
@@ -95,6 +95,7 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
                                 struct i2c_client *client, u8 val)
 {
        struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
+       int ret = -ENODEV;
 
        if (adap->algo->master_xfer) {
                struct i2c_msg msg;
@@ -104,17 +105,21 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
                msg.flags = 0;
                msg.len = 2;
                msg.buf = msgbuf;
-               return __i2c_transfer(adap, &msg, 1);
+               ret = __i2c_transfer(adap, &msg, 1);
+
+               if (ret >= 0 && ret != 1)
+                       ret = -EREMOTEIO;
        } else if (adap->algo->smbus_xfer) {
                union i2c_smbus_data data;
 
                data.byte = val;
-               return adap->algo->smbus_xfer(adap, client->addr,
-                                             client->flags, I2C_SMBUS_WRITE,
-                                             pdata->sel_reg_addr,
-                                             I2C_SMBUS_BYTE_DATA, &data);
-       } else
-               return -ENODEV;
+               ret = adap->algo->smbus_xfer(adap, client->addr,
+                                            client->flags, I2C_SMBUS_WRITE,
+                                            pdata->sel_reg_addr,
+                                            I2C_SMBUS_BYTE_DATA, &data);
+       }
+
+       return ret;
 }
 
 static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
@@ -127,10 +132,7 @@ static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
        /* Only select the channel if its different from the last channel */
        if (data->last_chan != regval) {
                err = mlxcpld_mux_reg_write(muxc->parent, client, regval);
-               if (err)
-                       data->last_chan = 0;
-               else
-                       data->last_chan = regval;
+               data->last_chan = err < 0 ? 0 : regval;
        }
 
        return err;
index 9a348ee4dc14deb9eb1686fd1a20dc672b73a5df..dd18b9ccb1f40b4f6ddf5904e1f6d529931801df 100644 (file)
@@ -167,6 +167,9 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
                buf[0] = val;
                msg.buf = buf;
                ret = __i2c_transfer(adap, &msg, 1);
+
+               if (ret >= 0 && ret != 1)
+                       ret = -EREMOTEIO;
        } else {
                union i2c_smbus_data data;
                ret = adap->algo->smbus_xfer(adap, client->addr,
@@ -195,7 +198,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
        /* Only select the channel if its different from the last channel */
        if (data->last_chan != regval) {
                ret = pca954x_reg_write(muxc->parent, client, regval);
-               data->last_chan = ret ? 0 : regval;
+               data->last_chan = ret < 0 ? 0 : regval;
        }
 
        return ret;
index 3273217ce80c8feecdf7d1b4d4c98c63264901b1..cc74a41bdb0d24d7e5eddd0f1e019ab01cea71c4 100644 (file)
@@ -150,12 +150,20 @@ static int tps6521x_pb_probe(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id tps6521x_pwrbtn_id_table[] = {
+       { "tps65218-pwrbutton", },
+       { "tps65217-pwrbutton", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps6521x_pwrbtn_id_table);
+
 static struct platform_driver tps6521x_pb_driver = {
        .probe  = tps6521x_pb_probe,
        .driver = {
                .name   = "tps6521x_pwrbutton",
                .of_match_table = of_tps6521x_pb_match,
        },
+       .id_table = tps6521x_pwrbtn_id_table,
 };
 module_platform_driver(tps6521x_pb_driver);
 
index c19dd820ea9b4baafb1b2d15ebb5031f464af9d0..2aeb034d5fb9cd4d0ce14e5c26a10fb6abf62538 100644 (file)
 #define RING_ENTRY_SIZE   sizeof(struct dma64dd)
 
 /* # entries in PDC dma ring */
-#define PDC_RING_ENTRIES  128
+#define PDC_RING_ENTRIES  512
+/*
+ * Minimum number of ring descriptor entries that must be free to tell mailbox
+ * framework that it can submit another request
+ */
+#define PDC_RING_SPACE_MIN  15
+
 #define PDC_RING_SIZE    (PDC_RING_ENTRIES * RING_ENTRY_SIZE)
 /* Rings are 8k aligned */
 #define RING_ALIGN_ORDER  13
  * Interrupt mask and status definitions. Enable interrupts for tx and rx on
  * ring 0
  */
-#define PDC_XMTINT_0         (24 + PDC_RINGSET)
 #define PDC_RCVINT_0         (16 + PDC_RINGSET)
-#define PDC_XMTINTEN_0       BIT(PDC_XMTINT_0)
 #define PDC_RCVINTEN_0       BIT(PDC_RCVINT_0)
-#define PDC_INTMASK  (PDC_XMTINTEN_0 | PDC_RCVINTEN_0)
+#define PDC_INTMASK         (PDC_RCVINTEN_0)
 #define PDC_LAZY_FRAMECOUNT  1
 #define PDC_LAZY_TIMEOUT     10000
 #define PDC_LAZY_INT  (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24))
 
 /*
  * Sets the following bits for write to transmit control reg:
- *  0    - XmtEn - enable activity on the tx channel
  * 11    - PtyChkDisable - parity check is disabled
  * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
  */
-#define PDC_TX_CTL              0x000C0801
+#define PDC_TX_CTL             0x000C0800
+
+/* Bit in tx control reg to enable tx channel */
+#define PDC_TX_ENABLE          0x1
 
 /*
  * Sets the following bits for write to receive control reg:
- * 0     - RcvEn - enable activity on the rx channel
  * 7:1   - RcvOffset - size in bytes of status region at start of rx frame buf
  * 9     - SepRxHdrDescEn - place start of new frames only in descriptors
  *                          that have StartOfFrame set
  * 11    - PtyChkDisable - parity check is disabled
  * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
  */
-#define PDC_RX_CTL              0x000C0E01
+#define PDC_RX_CTL             0x000C0E00
+
+/* Bit in rx control reg to enable rx channel */
+#define PDC_RX_ENABLE          0x1
 
 #define CRYPTO_D64_RS0_CD_MASK   ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1)
 
@@ -252,11 +260,29 @@ struct pdc_ring_alloc {
        u32         size;    /* ring allocation size in bytes */
 };
 
+/*
+ * context associated with a receive descriptor.
+ * @rxp_ctx: opaque context associated with frame that starts at each
+ *           rx ring index.
+ * @dst_sg:  Scatterlist used to form reply frames beginning at a given ring
+ *           index. Retained in order to unmap each sg after reply is processed.
+ * @rxin_numd: Number of rx descriptors associated with the message that starts
+ *             at a descriptor index. Not set for every index. For example,
+ *             if descriptor index i points to a scatterlist with 4 entries,
+ *             then the next three descriptor indexes don't have a value set.
+ * @resp_hdr: Virtual address of buffer used to catch DMA rx status
+ * @resp_hdr_daddr: physical address of DMA rx status buffer
+ */
+struct pdc_rx_ctx {
+       void *rxp_ctx;
+       struct scatterlist *dst_sg;
+       u32  rxin_numd;
+       void *resp_hdr;
+       dma_addr_t resp_hdr_daddr;
+};
+
 /* PDC state structure */
 struct pdc_state {
-       /* synchronize access to this PDC state structure */
-       spinlock_t pdc_lock;
-
        /* Index of the PDC whose state is in this structure instance */
        u8 pdc_idx;
 
@@ -272,13 +298,8 @@ struct pdc_state {
 
        unsigned int pdc_irq;
 
-       /*
-        * Last interrupt status read from PDC device. Saved in interrupt
-        * handler so the handler can clear the interrupt in the device,
-        * and the interrupt thread called later can know which interrupt
-        * bits are active.
-        */
-       unsigned long intstatus;
+       /* tasklet for deferred processing after DMA rx interrupt */
+       struct tasklet_struct rx_tasklet;
 
        /* Number of bytes of receive status prior to each rx frame */
        u32 rx_status_len;
@@ -369,11 +390,7 @@ struct pdc_state {
        /* Index of next rx descriptor to post. */
        u32  rxout;
 
-       /*
-        * opaque context associated with frame that starts at each
-        * rx ring index.
-        */
-       void *rxp_ctx[PDC_RING_ENTRIES];
+       struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES];
 
        /*
         * Scatterlists used to form request and reply frames beginning at a
@@ -381,27 +398,18 @@ struct pdc_state {
         * is processed
         */
        struct scatterlist *src_sg[PDC_RING_ENTRIES];
-       struct scatterlist *dst_sg[PDC_RING_ENTRIES];
-
-       /*
-        * Number of rx descriptors associated with the message that starts
-        * at this descriptor index. Not set for every index. For example,
-        * if descriptor index i points to a scatterlist with 4 entries, then
-        * the next three descriptor indexes don't have a value set.
-        */
-       u32  rxin_numd[PDC_RING_ENTRIES];
-
-       void *resp_hdr[PDC_RING_ENTRIES];
-       dma_addr_t resp_hdr_daddr[PDC_RING_ENTRIES];
 
        struct dentry *debugfs_stats;  /* debug FS stats file for this PDC */
 
        /* counters */
-       u32  pdc_requests;    /* number of request messages submitted */
-       u32  pdc_replies;     /* number of reply messages received */
-       u32  txnobuf;         /* count of tx ring full */
-       u32  rxnobuf;         /* count of rx ring full */
-       u32  rx_oflow;        /* count of rx overflows */
+       u32  pdc_requests;     /* number of request messages submitted */
+       u32  pdc_replies;      /* number of reply messages received */
+       u32  last_tx_not_done; /* too few tx descriptors to indicate done */
+       u32  tx_ring_full;     /* unable to accept msg because tx ring full */
+       u32  rx_ring_full;     /* unable to accept msg because rx ring full */
+       u32  txnobuf;          /* unable to create tx descriptor */
+       u32  rxnobuf;          /* unable to create rx descriptor */
+       u32  rx_oflow;         /* count of rx overflows */
 };
 
 /* Global variables */
@@ -434,20 +442,33 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf,
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "SPU %u stats:\n", pdcs->pdc_idx);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "PDC requests............%u\n",
+                              "PDC requests....................%u\n",
                               pdcs->pdc_requests);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "PDC responses...........%u\n",
+                              "PDC responses...................%u\n",
                               pdcs->pdc_replies);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "Tx err ring full........%u\n",
+                              "Tx not done.....................%u\n",
+                              pdcs->last_tx_not_done);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Tx ring full....................%u\n",
+                              pdcs->tx_ring_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Rx ring full....................%u\n",
+                              pdcs->rx_ring_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Tx desc write fail. Ring full...%u\n",
                               pdcs->txnobuf);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "Rx err ring full........%u\n",
+                              "Rx desc write fail. Ring full...%u\n",
                               pdcs->rxnobuf);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "Receive overflow........%u\n",
+                              "Receive overflow................%u\n",
                               pdcs->rx_oflow);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "Num frags in rx ring............%u\n",
+                              NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
+                                         pdcs->nrxpost));
 
        if (out_offset > out_count)
                out_offset = out_count;
@@ -480,17 +501,16 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs)
        if (!debugfs_dir)
                debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
 
-       pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, S_IRUSR,
+       /* S_IRUSR == 0400 */
+       pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400,
                                                  debugfs_dir, pdcs,
                                                  &pdc_debugfs_stats);
 }
 
 static void pdc_free_debugfs(void)
 {
-       if (debugfs_dir && simple_empty(debugfs_dir)) {
-               debugfs_remove_recursive(debugfs_dir);
-               debugfs_dir = NULL;
-       }
+       debugfs_remove_recursive(debugfs_dir);
+       debugfs_dir = NULL;
 }
 
 /**
@@ -505,17 +525,17 @@ pdc_build_rxd(struct pdc_state *pdcs, dma_addr_t dma_addr,
              u32 buf_len, u32 flags)
 {
        struct device *dev = &pdcs->pdev->dev;
+       struct dma64dd *rxd = &pdcs->rxd_64[pdcs->rxout];
 
        dev_dbg(dev,
                "Writing rx descriptor for PDC %u at index %u with length %u. flags %#x\n",
                pdcs->pdc_idx, pdcs->rxout, buf_len, flags);
 
-       iowrite32(lower_32_bits(dma_addr),
-                 (void *)&pdcs->rxd_64[pdcs->rxout].addrlow);
-       iowrite32(upper_32_bits(dma_addr),
-                 (void *)&pdcs->rxd_64[pdcs->rxout].addrhigh);
-       iowrite32(flags, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl1);
-       iowrite32(buf_len, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl2);
+       rxd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
+       rxd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
+       rxd->ctrl1 = cpu_to_le32(flags);
+       rxd->ctrl2 = cpu_to_le32(buf_len);
+
        /* bump ring index and return */
        pdcs->rxout = NEXTRXD(pdcs->rxout, pdcs->nrxpost);
 }
@@ -533,53 +553,50 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len,
              u32 flags)
 {
        struct device *dev = &pdcs->pdev->dev;
+       struct dma64dd *txd = &pdcs->txd_64[pdcs->txout];
 
        dev_dbg(dev,
                "Writing tx descriptor for PDC %u at index %u with length %u, flags %#x\n",
                pdcs->pdc_idx, pdcs->txout, buf_len, flags);
 
-       iowrite32(lower_32_bits(dma_addr),
-                 (void *)&pdcs->txd_64[pdcs->txout].addrlow);
-       iowrite32(upper_32_bits(dma_addr),
-                 (void *)&pdcs->txd_64[pdcs->txout].addrhigh);
-       iowrite32(flags, (void *)&pdcs->txd_64[pdcs->txout].ctrl1);
-       iowrite32(buf_len, (void *)&pdcs->txd_64[pdcs->txout].ctrl2);
+       txd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
+       txd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
+       txd->ctrl1 = cpu_to_le32(flags);
+       txd->ctrl2 = cpu_to_le32(buf_len);
 
        /* bump ring index and return */
        pdcs->txout = NEXTTXD(pdcs->txout, pdcs->ntxpost);
 }
 
 /**
- * pdc_receive() - Receive a response message from a given SPU.
+ * pdc_receive_one() - Receive a response message from a given SPU.
  * @pdcs:    PDC state for the SPU to receive from
- * @mssg:    mailbox message to be returned to client
  *
  * When the return code indicates success, the response message is available in
  * the receive buffers provided prior to submission of the request.
  *
- * Input:
- *   pdcs - PDC state structure for the SPU to be polled
- *   mssg - mailbox message to be returned to client. This function sets the
- *         context pointer on the message to help the client associate the
- *         response with a request.
- *
  * Return:  PDC_SUCCESS if one or more receive descriptors was processed
  *          -EAGAIN indicates that no response message is available
  *          -EIO an error occurred
  */
 static int
-pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
+pdc_receive_one(struct pdc_state *pdcs)
 {
        struct device *dev = &pdcs->pdev->dev;
+       struct mbox_controller *mbc;
+       struct mbox_chan *chan;
+       struct brcm_message mssg;
        u32 len, rx_status;
        u32 num_frags;
-       int i;
        u8 *resp_hdr;    /* virtual addr of start of resp message DMA header */
        u32 frags_rdy;   /* number of fragments ready to read */
        u32 rx_idx;      /* ring index of start of receive frame */
        dma_addr_t resp_hdr_daddr;
+       struct pdc_rx_ctx *rx_ctx;
 
-       spin_lock(&pdcs->pdc_lock);
+       mbc = &pdcs->mbc;
+       chan = &mbc->chans[0];
+       mssg.type = BRCM_MESSAGE_SPU;
 
        /*
         * return if a complete response message is not yet ready.
@@ -587,47 +604,34 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
         * to read.
         */
        frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost);
-       if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) {
-               /* See if the hw has written more fragments than we know */
-               pdcs->last_rx_curr =
-                   (ioread32((void *)&pdcs->rxregs_64->status0) &
-                    CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
-               frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
-                                      pdcs->nrxpost);
-               if ((frags_rdy == 0) ||
-                   (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) {
-                       /* No response ready */
-                       spin_unlock(&pdcs->pdc_lock);
-                       return -EAGAIN;
-               }
-               /* can't read descriptors/data until write index is read */
-               rmb();
-       }
+       if ((frags_rdy == 0) ||
+           (frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd))
+               /* No response ready */
+               return -EAGAIN;
 
        num_frags = pdcs->txin_numd[pdcs->txin];
+       WARN_ON(num_frags == 0);
+
        dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin],
                     sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE);
 
-       for (i = 0; i < num_frags; i++)
-               pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost);
+       pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost;
 
        dev_dbg(dev, "PDC %u reclaimed %d tx descriptors",
                pdcs->pdc_idx, num_frags);
 
        rx_idx = pdcs->rxin;
-       num_frags = pdcs->rxin_numd[rx_idx];
+       rx_ctx = &pdcs->rx_ctx[rx_idx];
+       num_frags = rx_ctx->rxin_numd;
        /* Return opaque context with result */
-       mssg->ctx = pdcs->rxp_ctx[rx_idx];
-       pdcs->rxp_ctx[rx_idx] = NULL;
-       resp_hdr = pdcs->resp_hdr[rx_idx];
-       resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx];
-       dma_unmap_sg(dev, pdcs->dst_sg[rx_idx],
-                    sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE);
-
-       for (i = 0; i < num_frags; i++)
-               pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost);
+       mssg.ctx = rx_ctx->rxp_ctx;
+       rx_ctx->rxp_ctx = NULL;
+       resp_hdr = rx_ctx->resp_hdr;
+       resp_hdr_daddr = rx_ctx->resp_hdr_daddr;
+       dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg),
+                    DMA_FROM_DEVICE);
 
-       spin_unlock(&pdcs->pdc_lock);
+       pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost;
 
        dev_dbg(dev, "PDC %u reclaimed %d rx descriptors",
                pdcs->pdc_idx, num_frags);
@@ -659,12 +663,35 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg)
 
        dma_pool_free(pdcs->rx_buf_pool, resp_hdr, resp_hdr_daddr);
 
+       mbox_chan_received_data(chan, &mssg);
+
        pdcs->pdc_replies++;
-       /* if we read one or more rx descriptors, claim success */
-       if (num_frags > 0)
-               return PDC_SUCCESS;
-       else
-               return -EIO;
+       return PDC_SUCCESS;
+}
+
+/**
+ * pdc_receive() - Process as many responses as are available in the rx ring.
+ * @pdcs:  PDC state
+ *
+ * Called within the hard IRQ.
+ * Return:
+ */
+static int
+pdc_receive(struct pdc_state *pdcs)
+{
+       int rx_status;
+
+       /* read last_rx_curr from register once */
+       pdcs->last_rx_curr =
+           (ioread32(&pdcs->rxregs_64->status0) &
+            CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
+
+       do {
+               /* Could be many frames ready */
+               rx_status = pdc_receive_one(pdcs);
+       } while (rx_status == PDC_SUCCESS);
+
+       return 0;
 }
 
 /**
@@ -766,8 +793,8 @@ static int pdc_tx_list_final(struct pdc_state *pdcs)
         * before chip starts to process new request
         */
        wmb();
-       iowrite32(pdcs->rxout << 4, (void *)&pdcs->rxregs_64->ptr);
-       iowrite32(pdcs->txout << 4, (void *)&pdcs->txregs_64->ptr);
+       iowrite32(pdcs->rxout << 4, &pdcs->rxregs_64->ptr);
+       iowrite32(pdcs->txout << 4, &pdcs->txregs_64->ptr);
        pdcs->pdc_requests++;
 
        return PDC_SUCCESS;
@@ -796,6 +823,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
        u32 rx_pkt_cnt = 1;     /* Adding a single rx buffer */
        dma_addr_t daddr;
        void *vaddr;
+       struct pdc_rx_ctx *rx_ctx;
 
        rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
                                              pdcs->nrxpost);
@@ -806,7 +834,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
 
        /* allocate a buffer for the dma rx status */
        vaddr = dma_pool_zalloc(pdcs->rx_buf_pool, GFP_ATOMIC, &daddr);
-       if (!vaddr)
+       if (unlikely(!vaddr))
                return -ENOMEM;
 
        /*
@@ -819,15 +847,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
 
        /* This is always the first descriptor in the receive sequence */
        flags = D64_CTRL1_SOF;
-       pdcs->rxin_numd[pdcs->rx_msg_start] = 1;
+       pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1;
 
        if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
                flags |= D64_CTRL1_EOT;
 
-       pdcs->rxp_ctx[pdcs->rxout] = ctx;
-       pdcs->dst_sg[pdcs->rxout] = dst_sg;
-       pdcs->resp_hdr[pdcs->rxout] = vaddr;
-       pdcs->resp_hdr_daddr[pdcs->rxout] = daddr;
+       rx_ctx = &pdcs->rx_ctx[pdcs->rxout];
+       rx_ctx->rxp_ctx = ctx;
+       rx_ctx->dst_sg = dst_sg;
+       rx_ctx->resp_hdr = vaddr;
+       rx_ctx->resp_hdr_daddr = daddr;
        pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags);
        return PDC_SUCCESS;
 }
@@ -895,7 +924,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
                desc_w++;
                sg = sg_next(sg);
        }
-       pdcs->rxin_numd[pdcs->rx_msg_start] += desc_w;
+       pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w;
 
        return PDC_SUCCESS;
 }
@@ -903,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
 /**
  * pdc_irq_handler() - Interrupt handler called in interrupt context.
  * @irq:      Interrupt number that has fired
- * @cookie:   PDC state for DMA engine that generated the interrupt
+ * @data:     device struct for DMA engine that generated the interrupt
  *
  * We have to clear the device interrupt status flags here. So cache the
  * status for later use in the thread function. Other than that, just return
@@ -912,88 +941,39 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
  * Return: IRQ_WAKE_THREAD if interrupt is ours
  *         IRQ_NONE otherwise
  */
-static irqreturn_t pdc_irq_handler(int irq, void *cookie)
+static irqreturn_t pdc_irq_handler(int irq, void *data)
 {
-       struct pdc_state *pdcs = cookie;
+       struct device *dev = (struct device *)data;
+       struct pdc_state *pdcs = dev_get_drvdata(dev);
        u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
 
-       if (intstatus & PDC_XMTINTEN_0)
-               set_bit(PDC_XMTINT_0, &pdcs->intstatus);
-       if (intstatus & PDC_RCVINTEN_0)
-               set_bit(PDC_RCVINT_0, &pdcs->intstatus);
+       if (unlikely(intstatus == 0))
+               return IRQ_NONE;
+
+       /* Disable interrupts until soft handler runs */
+       iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
 
        /* Clear interrupt flags in device */
        iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
 
        /* Wakeup IRQ thread */
-       if (pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))
-               return IRQ_WAKE_THREAD;
-
-       return IRQ_NONE;
+       tasklet_schedule(&pdcs->rx_tasklet);
+       return IRQ_HANDLED;
 }
 
 /**
- * pdc_irq_thread() - Function invoked on deferred thread when a DMA tx has
- * completed or data is available to receive.
- * @irq:    Interrupt number
- * @cookie: PDC state for PDC that generated the interrupt
- *
- * On DMA tx complete, notify the mailbox client. On DMA rx complete, process
- * as many SPU response messages as are available and send each to the mailbox
- * client.
- *
- * Return: IRQ_HANDLED if we recognized and handled the interrupt
- *         IRQ_NONE otherwise
+ * pdc_tasklet_cb() - Tasklet callback that runs the deferred processing after
+ * a DMA receive interrupt. Reenables the receive interrupt.
+ * @data: PDC state structure
  */
-static irqreturn_t pdc_irq_thread(int irq, void *cookie)
+static void pdc_tasklet_cb(unsigned long data)
 {
-       struct pdc_state *pdcs = cookie;
-       struct mbox_controller *mbc;
-       struct mbox_chan *chan;
-       bool tx_int;
-       bool rx_int;
-       int rx_status;
-       struct brcm_message mssg;
+       struct pdc_state *pdcs = (struct pdc_state *)data;
 
-       tx_int = test_and_clear_bit(PDC_XMTINT_0, &pdcs->intstatus);
-       rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus);
+       pdc_receive(pdcs);
 
-       if (pdcs && (tx_int || rx_int)) {
-               dev_dbg(&pdcs->pdev->dev,
-                       "%s() got irq %d with tx_int %s, rx_int %s",
-                       __func__, irq,
-                       tx_int ? "set" : "clear", rx_int ? "set" : "clear");
-
-               mbc = &pdcs->mbc;
-               chan = &mbc->chans[0];
-
-               if (tx_int) {
-                       dev_dbg(&pdcs->pdev->dev, "%s(): tx done", __func__);
-                       /* only one frame in flight at a time */
-                       mbox_chan_txdone(chan, PDC_SUCCESS);
-               }
-               if (rx_int) {
-                       while (1) {
-                               /* Could be many frames ready */
-                               memset(&mssg, 0, sizeof(mssg));
-                               mssg.type = BRCM_MESSAGE_SPU;
-                               rx_status = pdc_receive(pdcs, &mssg);
-                               if (rx_status >= 0) {
-                                       dev_dbg(&pdcs->pdev->dev,
-                                               "%s(): invoking client rx cb",
-                                               __func__);
-                                       mbox_chan_received_data(chan, &mssg);
-                               } else {
-                                       dev_dbg(&pdcs->pdev->dev,
-                                               "%s(): no SPU response available",
-                                               __func__);
-                                       break;
-                               }
-                       }
-               }
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
+       /* reenable interrupts */
+       iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
 }
 
 /**
@@ -1016,14 +996,14 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
 
        /* Allocate tx ring */
        tx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &tx.dmabase);
-       if (!tx.vbase) {
+       if (unlikely(!tx.vbase)) {
                err = -ENOMEM;
                goto done;
        }
 
        /* Allocate rx ring */
        rx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &rx.dmabase);
-       if (!rx.vbase) {
+       if (unlikely(!rx.vbase)) {
                err = -ENOMEM;
                goto fail_dealloc;
        }
@@ -1033,9 +1013,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
        dev_dbg(dev, " - base DMA addr of rx ring      %pad", &rx.dmabase);
        dev_dbg(dev, " - base virtual addr of rx ring  %p", rx.vbase);
 
-       /* lock after ring allocation to avoid scheduling while atomic */
-       spin_lock(&pdcs->pdc_lock);
-
        memcpy(&pdcs->tx_ring_alloc, &tx, sizeof(tx));
        memcpy(&pdcs->rx_ring_alloc, &rx, sizeof(rx));
 
@@ -1053,40 +1030,52 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset)
 
        /* Tell device the base DMA address of each ring */
        dma_reg = &pdcs->regs->dmaregs[ringset];
+
+       /* But first disable DMA and set curptr to 0 for both TX & RX */
+       iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
+       iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)),
+                 &dma_reg->dmarcv.control);
+       iowrite32(0, &dma_reg->dmaxmt.ptr);
+       iowrite32(0, &dma_reg->dmarcv.ptr);
+
+       /* Set base DMA addresses */
        iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmaxmt.addrlow);
+                 &dma_reg->dmaxmt.addrlow);
        iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmaxmt.addrhigh);
+                 &dma_reg->dmaxmt.addrhigh);
 
        iowrite32(lower_32_bits(pdcs->rx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmarcv.addrlow);
+                 &dma_reg->dmarcv.addrlow);
        iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase),
-                 (void *)&dma_reg->dmarcv.addrhigh);
+                 &dma_reg->dmarcv.addrhigh);
+
+       /* Re-enable DMA */
+       iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control);
+       iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)),
+                 &dma_reg->dmarcv.control);
 
        /* Initialize descriptors */
        for (i = 0; i < PDC_RING_ENTRIES; i++) {
                /* Every tx descriptor can be used for start of frame. */
                if (i != pdcs->ntxpost) {
                        iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF,
-                                 (void *)&pdcs->txd_64[i].ctrl1);
+                                 &pdcs->txd_64[i].ctrl1);
                } else {
                        /* Last descriptor in ringset. Set End of Table. */
                        iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF |
-                                 D64_CTRL1_EOT,
-                                 (void *)&pdcs->txd_64[i].ctrl1);
+                                 D64_CTRL1_EOT, &pdcs->txd_64[i].ctrl1);
                }
 
                /* Every rx descriptor can be used for start of frame */
                if (i != pdcs->nrxpost) {
                        iowrite32(D64_CTRL1_SOF,
-                                 (void *)&pdcs->rxd_64[i].ctrl1);
+                                 &pdcs->rxd_64[i].ctrl1);
                } else {
                        /* Last descriptor in ringset. Set End of Table. */
                        iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOT,
-                                 (void *)&pdcs->rxd_64[i].ctrl1);
+                                 &pdcs->rxd_64[i].ctrl1);
                }
        }
-       spin_unlock(&pdcs->pdc_lock);
        return PDC_SUCCESS;
 
 fail_dealloc:
@@ -1110,6 +1099,80 @@ static void pdc_ring_free(struct pdc_state *pdcs)
        }
 }
 
+/**
+ * pdc_desc_count() - Count the number of DMA descriptors that will be required
+ * for a given scatterlist. Account for the max length of a DMA buffer.
+ * @sg:    Scatterlist to be DMA'd
+ * Return: Number of descriptors required
+ */
+static u32 pdc_desc_count(struct scatterlist *sg)
+{
+       u32 cnt = 0;
+
+       while (sg) {
+               cnt += ((sg->length / PDC_DMA_BUF_MAX) + 1);
+               sg = sg_next(sg);
+       }
+       return cnt;
+}
+
+/**
+ * pdc_rings_full() - Check whether the tx ring has room for tx_cnt descriptors
+ * and the rx ring has room for rx_cnt descriptors.
+ * @pdcs:  PDC state
+ * @tx_cnt: The number of descriptors required in the tx ring
+ * @rx_cnt: The number of descriptors required i the rx ring
+ *
+ * Return: true if one of the rings does not have enough space
+ *         false if sufficient space is available in both rings
+ */
+static bool pdc_rings_full(struct pdc_state *pdcs, int tx_cnt, int rx_cnt)
+{
+       u32 rx_avail;
+       u32 tx_avail;
+       bool full = false;
+
+       /* Check if the tx and rx rings are likely to have enough space */
+       rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
+                                             pdcs->nrxpost);
+       if (unlikely(rx_cnt > rx_avail)) {
+               pdcs->rx_ring_full++;
+               full = true;
+       }
+
+       if (likely(!full)) {
+               tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout,
+                                                     pdcs->ntxpost);
+               if (unlikely(tx_cnt > tx_avail)) {
+                       pdcs->tx_ring_full++;
+                       full = true;
+               }
+       }
+       return full;
+}
+
+/**
+ * pdc_last_tx_done() - If both the tx and rx rings have at least
+ * PDC_RING_SPACE_MIN descriptors available, then indicate that the mailbox
+ * framework can submit another message.
+ * @chan:  mailbox channel to check
+ * Return: true if PDC can accept another message on this channel
+ */
+static bool pdc_last_tx_done(struct mbox_chan *chan)
+{
+       struct pdc_state *pdcs = chan->con_priv;
+       bool ret;
+
+       if (unlikely(pdc_rings_full(pdcs, PDC_RING_SPACE_MIN,
+                                   PDC_RING_SPACE_MIN))) {
+               pdcs->last_tx_not_done++;
+               ret = false;
+       } else {
+               ret = true;
+       }
+       return ret;
+}
+
 /**
  * pdc_send_data() - mailbox send_data function
  * @chan:      The mailbox channel on which the data is sent. The channel
@@ -1141,29 +1204,43 @@ static int pdc_send_data(struct mbox_chan *chan, void *data)
        int src_nent;
        int dst_nent;
        int nent;
+       u32 tx_desc_req;
+       u32 rx_desc_req;
 
-       if (mssg->type != BRCM_MESSAGE_SPU)
+       if (unlikely(mssg->type != BRCM_MESSAGE_SPU))
                return -ENOTSUPP;
 
        src_nent = sg_nents(mssg->spu.src);
-       if (src_nent) {
+       if (likely(src_nent)) {
                nent = dma_map_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE);
-               if (nent == 0)
+               if (unlikely(nent == 0))
                        return -EIO;
        }
 
        dst_nent = sg_nents(mssg->spu.dst);
-       if (dst_nent) {
+       if (likely(dst_nent)) {
                nent = dma_map_sg(dev, mssg->spu.dst, dst_nent,
                                  DMA_FROM_DEVICE);
-               if (nent == 0) {
+               if (unlikely(nent == 0)) {
                        dma_unmap_sg(dev, mssg->spu.src, src_nent,
                                     DMA_TO_DEVICE);
                        return -EIO;
                }
        }
 
-       spin_lock(&pdcs->pdc_lock);
+       /*
+        * Check if the tx and rx rings have enough space. Do this prior to
+        * writing any tx or rx descriptors. Need to ensure that we do not write
+        * a partial set of descriptors, or write just rx descriptors but
+        * corresponding tx descriptors don't fit. Note that we want this check
+        * and the entire sequence of descriptor to happen without another
+        * thread getting in. The channel spin lock in the mailbox framework
+        * ensures this.
+        */
+       tx_desc_req = pdc_desc_count(mssg->spu.src);
+       rx_desc_req = pdc_desc_count(mssg->spu.dst);
+       if (unlikely(pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)))
+               return -ENOSPC;
 
        /* Create rx descriptors to SPU catch response */
        err = pdc_rx_list_init(pdcs, mssg->spu.dst, mssg->ctx);
@@ -1173,9 +1250,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data)
        err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src);
        err |= pdc_tx_list_final(pdcs); /* initiate transfer */
 
-       spin_unlock(&pdcs->pdc_lock);
-
-       if (err)
+       if (unlikely(err))
                dev_err(&pdcs->pdev->dev,
                        "%s failed with error %d", __func__, err);
 
@@ -1224,32 +1299,50 @@ void pdc_hw_init(struct pdc_state *pdcs)
        /* initialize data structures */
        pdcs->regs = (struct pdc_regs *)pdcs->pdc_reg_vbase;
        pdcs->txregs_64 = (struct dma64_regs *)
-           (void *)(((u8 *)pdcs->pdc_reg_vbase) +
+           (((u8 *)pdcs->pdc_reg_vbase) +
                     PDC_TXREGS_OFFSET + (sizeof(struct dma64) * ringset));
        pdcs->rxregs_64 = (struct dma64_regs *)
-           (void *)(((u8 *)pdcs->pdc_reg_vbase) +
+           (((u8 *)pdcs->pdc_reg_vbase) +
                     PDC_RXREGS_OFFSET + (sizeof(struct dma64) * ringset));
 
        pdcs->ntxd = PDC_RING_ENTRIES;
        pdcs->nrxd = PDC_RING_ENTRIES;
        pdcs->ntxpost = PDC_RING_ENTRIES - 1;
        pdcs->nrxpost = PDC_RING_ENTRIES - 1;
-       pdcs->regs->intmask = 0;
+       iowrite32(0, &pdcs->regs->intmask);
 
        dma_reg = &pdcs->regs->dmaregs[ringset];
-       iowrite32(0, (void *)&dma_reg->dmaxmt.ptr);
-       iowrite32(0, (void *)&dma_reg->dmarcv.ptr);
 
-       iowrite32(PDC_TX_CTL, (void *)&dma_reg->dmaxmt.control);
+       /* Configure DMA but will enable later in pdc_ring_init() */
+       iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
 
        iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
-                 (void *)&dma_reg->dmarcv.control);
+                 &dma_reg->dmarcv.control);
+
+       /* Reset current index pointers after making sure DMA is disabled */
+       iowrite32(0, &dma_reg->dmaxmt.ptr);
+       iowrite32(0, &dma_reg->dmarcv.ptr);
 
        if (pdcs->pdc_resp_hdr_len == PDC_SPU2_RESP_HDR_LEN)
                iowrite32(PDC_CKSUM_CTRL,
                          pdcs->pdc_reg_vbase + PDC_CKSUM_CTRL_OFFSET);
 }
 
+/**
+ * pdc_hw_disable() - Disable the tx and rx control in the hw.
+ * @pdcs: PDC state structure
+ *
+ */
+static void pdc_hw_disable(struct pdc_state *pdcs)
+{
+       struct dma64 *dma_reg;
+
+       dma_reg = &pdcs->regs->dmaregs[PDC_RINGSET];
+       iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
+       iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
+                 &dma_reg->dmarcv.control);
+}
+
 /**
  * pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata
  * header returned with each response message.
@@ -1301,8 +1394,6 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
        struct device_node *dn = pdev->dev.of_node;
        int err;
 
-       pdcs->intstatus = 0;
-
        /* interrupt configuration */
        iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
        iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase + PDC_RCVLAZY0_OFFSET);
@@ -1311,11 +1402,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
        pdcs->pdc_irq = irq_of_parse_and_map(dn, 0);
        dev_dbg(dev, "pdc device %s irq %u for pdcs %p",
                dev_name(dev), pdcs->pdc_irq, pdcs);
-       err = devm_request_threaded_irq(dev, pdcs->pdc_irq,
-                                       pdc_irq_handler,
-                                       pdc_irq_thread, 0, dev_name(dev), pdcs);
+
+       err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0,
+                              dev_name(dev), dev);
        if (err) {
-               dev_err(dev, "threaded tx IRQ %u request failed with err %d\n",
+               dev_err(dev, "IRQ %u request failed with err %d\n",
                        pdcs->pdc_irq, err);
                return err;
        }
@@ -1324,6 +1415,7 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
 
 static const struct mbox_chan_ops pdc_mbox_chan_ops = {
        .send_data = pdc_send_data,
+       .last_tx_done = pdc_last_tx_done,
        .startup = pdc_startup,
        .shutdown = pdc_shutdown
 };
@@ -1356,8 +1448,9 @@ static int pdc_mb_init(struct pdc_state *pdcs)
        if (!mbc->chans)
                return -ENOMEM;
 
-       mbc->txdone_irq = true;
-       mbc->txdone_poll = false;
+       mbc->txdone_irq = false;
+       mbc->txdone_poll = true;
+       mbc->txpoll_period = 1;
        for (chan_index = 0; chan_index < mbc->num_chans; chan_index++)
                mbc->chans[chan_index].con_priv = pdcs;
 
@@ -1427,7 +1520,6 @@ static int pdc_probe(struct platform_device *pdev)
                goto cleanup;
        }
 
-       spin_lock_init(&pdcs->pdc_lock);
        pdcs->pdev = pdev;
        platform_set_drvdata(pdev, pdcs);
        pdcs->pdc_idx = pdcg.num_spu;
@@ -1473,6 +1565,9 @@ static int pdc_probe(struct platform_device *pdev)
 
        pdc_hw_init(pdcs);
 
+       /* Init tasklet for deferred DMA rx processing */
+       tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long)pdcs);
+
        err = pdc_interrupts_init(pdcs);
        if (err)
                goto cleanup_buf_pool;
@@ -1489,6 +1584,7 @@ static int pdc_probe(struct platform_device *pdev)
        return PDC_SUCCESS;
 
 cleanup_buf_pool:
+       tasklet_kill(&pdcs->rx_tasklet);
        dma_pool_destroy(pdcs->rx_buf_pool);
 
 cleanup_ring_pool:
@@ -1504,6 +1600,10 @@ static int pdc_remove(struct platform_device *pdev)
 
        pdc_free_debugfs();
 
+       tasklet_kill(&pdcs->rx_tasklet);
+
+       pdc_hw_disable(pdcs);
+
        mbox_controller_unregister(&pdcs->mbc);
 
        dma_pool_destroy(pdcs->rx_buf_pool);
index a334db5c9f1c126939873555671302b97ebecae9..41bcd339b68a1987eb1a62c1a6653c711341e350 100644 (file)
@@ -403,6 +403,7 @@ static const struct of_device_id sti_mailbox_match[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, sti_mailbox_match);
 
 static int sti_mbox_probe(struct platform_device *pdev)
 {
index 9ca96e9db6bfb137863250f8b27b2232fc1c449d..9c79f8019d2a5f2f08df00ea6762f4398013c482 100644 (file)
 
 #include <linux/debugfs.h>
 #include <linux/err.h>
+#include <linux/fs.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/mailbox_client.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 
@@ -39,6 +41,8 @@ struct mbox_test_device {
        char                    *signal;
        char                    *message;
        spinlock_t              lock;
+       wait_queue_head_t       waitq;
+       struct fasync_struct    *async_queue;
 };
 
 static ssize_t mbox_test_signal_write(struct file *filp,
@@ -81,6 +85,13 @@ static const struct file_operations mbox_test_signal_ops = {
        .llseek = generic_file_llseek,
 };
 
+static int mbox_test_message_fasync(int fd, struct file *filp, int on)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+
+       return fasync_helper(fd, filp, on, &tdev->async_queue);
+}
+
 static ssize_t mbox_test_message_write(struct file *filp,
                                       const char __user *userbuf,
                                       size_t count, loff_t *ppos)
@@ -138,6 +149,20 @@ out:
        return ret < 0 ? ret : count;
 }
 
+static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
+{
+       unsigned char data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tdev->lock, flags);
+       data = tdev->rx_buffer[0];
+       spin_unlock_irqrestore(&tdev->lock, flags);
+
+       if (data != '\0')
+               return true;
+       return false;
+}
+
 static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
                                      size_t count, loff_t *ppos)
 {
@@ -147,6 +172,8 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
        int l = 0;
        int ret;
 
+       DECLARE_WAITQUEUE(wait, current);
+
        touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
        if (!touser)
                return -ENOMEM;
@@ -155,15 +182,29 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
                ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
                ret = simple_read_from_buffer(userbuf, count, ppos,
                                              touser, ret);
-               goto out;
+               goto kfree_err;
        }
 
-       if (tdev->rx_buffer[0] == '\0') {
-               ret = snprintf(touser, 9, "<EMPTY>\n");
-               ret = simple_read_from_buffer(userbuf, count, ppos,
-                                             touser, ret);
-               goto out;
-       }
+       add_wait_queue(&tdev->waitq, &wait);
+
+       do {
+               __set_current_state(TASK_INTERRUPTIBLE);
+
+               if (mbox_test_message_data_ready(tdev))
+                       break;
+
+               if (filp->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       goto waitq_err;
+               }
+
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       goto waitq_err;
+               }
+               schedule();
+
+       } while (1);
 
        spin_lock_irqsave(&tdev->lock, flags);
 
@@ -185,14 +226,31 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
        spin_unlock_irqrestore(&tdev->lock, flags);
 
        ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
-out:
+waitq_err:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tdev->waitq, &wait);
+kfree_err:
        kfree(touser);
        return ret;
 }
 
+static unsigned int
+mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
+{
+       struct mbox_test_device *tdev = filp->private_data;
+
+       poll_wait(filp, &tdev->waitq, wait);
+
+       if (mbox_test_message_data_ready(tdev))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
 static const struct file_operations mbox_test_message_ops = {
        .write  = mbox_test_message_write,
        .read   = mbox_test_message_read,
+       .fasync = mbox_test_message_fasync,
+       .poll   = mbox_test_message_poll,
        .open   = simple_open,
        .llseek = generic_file_llseek,
 };
@@ -234,6 +292,10 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message)
                memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
        }
        spin_unlock_irqrestore(&tdev->lock, flags);
+
+       wake_up_interruptible(&tdev->waitq);
+
+       kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
 }
 
 static void mbox_test_prepare_message(struct mbox_client *client, void *message)
@@ -290,6 +352,7 @@ static int mbox_test_probe(struct platform_device *pdev)
 {
        struct mbox_test_device *tdev;
        struct resource *res;
+       resource_size_t size;
        int ret;
 
        tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
@@ -298,14 +361,21 @@ static int mbox_test_probe(struct platform_device *pdev)
 
        /* It's okay for MMIO to be NULL */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       size = resource_size(res);
        tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(tdev->tx_mmio))
+       if (PTR_ERR(tdev->tx_mmio) == -EBUSY)
+               /* if reserved area in SRAM, try just ioremap */
+               tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
+       else if (IS_ERR(tdev->tx_mmio))
                tdev->tx_mmio = NULL;
 
        /* If specified, second reg entry is Rx MMIO */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       size = resource_size(res);
        tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(tdev->rx_mmio))
+       if (PTR_ERR(tdev->rx_mmio) == -EBUSY)
+               tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
+       else if (IS_ERR(tdev->rx_mmio))
                tdev->rx_mmio = tdev->tx_mmio;
 
        tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
@@ -334,6 +404,7 @@ static int mbox_test_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       init_waitqueue_head(&tdev->waitq);
        dev_info(&pdev->dev, "Successfully registered\n");
 
        return 0;
@@ -357,6 +428,7 @@ static const struct of_device_id mbox_test_match[] = {
        { .compatible = "mailbox-test" },
        {},
 };
+MODULE_DEVICE_TABLE(of, mbox_test_match);
 
 static struct platform_driver mbox_test_driver = {
        .driver = {
index 1ed0584f494e415d5529cdf28612c1e701b6e721..4ce3b6f118304048c0fb4d0db7c1d4da7463e8e7 100644 (file)
@@ -40,6 +40,22 @@ config MFD_ACT8945A
          linear regulators, along with a complete ActivePath battery
          charger.
 
+config MFD_SUN4I_GPADC
+       tristate "Allwinner sunxi platforms' GPADC MFD driver"
+       select MFD_CORE
+       select REGMAP_MMIO
+       select REGMAP_IRQ
+       depends on ARCH_SUNXI || COMPILE_TEST
+       help
+         Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC.
+         This driver will only map the hardware interrupt and registers, you
+         have to select individual drivers based on this MFD to be able to use
+         the ADC or the thermal sensor. This will try to probe the ADC driver
+         sun4i-gpadc-iio and the hwmon driver iio_hwmon.
+
+         To compile this driver as a module, choose M here: the module will be
+         called sun4i-gpadc.
+
 config MFD_AS3711
        bool "AMS AS3711"
        select MFD_CORE
@@ -293,6 +309,7 @@ config MFD_DLN2
 
 config MFD_EXYNOS_LPASS
        tristate "Samsung Exynos SoC Low Power Audio Subsystem"
+       depends on ARCH_EXYNOS || COMPILE_TEST
        select MFD_CORE
        select REGMAP_MMIO
        help
@@ -563,7 +580,7 @@ config MFD_MAX14577
 config MFD_MAX77620
        bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
        depends on I2C=y
-       depends on OF
+       depends on OF || COMPILE_TEST
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -578,7 +595,7 @@ config MFD_MAX77620
 config MFD_MAX77686
        tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
        depends on I2C
-       depends on OF
+       depends on OF || COMPILE_TEST
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -877,7 +894,8 @@ config MFD_RN5T618
        select MFD_CORE
        select REGMAP_I2C
        help
-         Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC.
+         Say yes here to add support for the Ricoh RN5T567,
+          RN5T618, RC5T619 PMIC.
          This driver provides common support for accessing the device,
          additional drivers must be enabled in order to use the
          functionality of the device.
@@ -951,7 +969,7 @@ config MFD_SMSC
 
 config ABX500_CORE
        bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
-       default y if ARCH_U300 || ARCH_U8500
+       default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST
        help
          Say yes here if you have the ABX500 Mixed Signal IC family
          chips. This core driver expose register access functions.
index 7bb5a50127cbb32bf3c2959705eafbb7c741a65b..dda4d4f73ad743b7cdde1f085dd494c0a1701656 100644 (file)
@@ -211,3 +211,4 @@ obj-$(CONFIG_INTEL_SOC_PMIC)        += intel-soc-pmic.o
 obj-$(CONFIG_MFD_MT6397)       += mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+obj-$(CONFIG_MFD_SUN4I_GPADC)  += sun4i-gpadc.o
index 6a5a98806cb817a28c782117a2a171c6975525a5..099635bed18850a7efc4e781688cee434e48e04a 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/notifier.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
@@ -628,20 +628,10 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
  exit_no_debugfs:
        return;
 }
-static inline void ab3100_remove_debugfs(void)
-{
-       debugfs_remove(ab3100_set_reg_file);
-       debugfs_remove(ab3100_get_reg_file);
-       debugfs_remove(ab3100_reg_file);
-       debugfs_remove(ab3100_dir);
-}
 #else
 static inline void ab3100_setup_debugfs(struct ab3100 *ab3100)
 {
 }
-static inline void ab3100_remove_debugfs(void)
-{
-}
 #endif
 
 /*
@@ -949,45 +939,22 @@ static int ab3100_probe(struct i2c_client *client,
        return err;
 }
 
-static int ab3100_remove(struct i2c_client *client)
-{
-       struct ab3100 *ab3100 = i2c_get_clientdata(client);
-
-       /* Unregister subdevices */
-       mfd_remove_devices(&client->dev);
-       ab3100_remove_debugfs();
-       i2c_unregister_device(ab3100->testreg_client);
-       return 0;
-}
-
 static const struct i2c_device_id ab3100_id[] = {
        { "ab3100", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, ab3100_id);
 
 static struct i2c_driver ab3100_driver = {
        .driver = {
-               .name   = "ab3100",
+               .name                   = "ab3100",
+               .suppress_bind_attrs    = true,
        },
        .id_table       = ab3100_id,
        .probe          = ab3100_probe,
-       .remove         = ab3100_remove,
 };
 
 static int __init ab3100_i2c_init(void)
 {
        return i2c_add_driver(&ab3100_driver);
 }
-
-static void __exit ab3100_i2c_exit(void)
-{
-       i2c_del_driver(&ab3100_driver);
-}
-
 subsys_initcall(ab3100_i2c_init);
-module_exit(ab3100_i2c_exit);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
-MODULE_DESCRIPTION("AB3100 core driver");
-MODULE_LICENSE("GPL");
index 589eebfc13df9faf8ef5fed5c993e428a5a5ccf9..6e00124cef01a0772f24c4c5d880ec3f66332ef2 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/irqdomain.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
@@ -123,6 +123,10 @@ static DEFINE_SPINLOCK(on_stat_lock);
 static u8 turn_on_stat_mask = 0xFF;
 static u8 turn_on_stat_set;
 static bool no_bm; /* No battery management */
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
 module_param(no_bm, bool, S_IRUGO);
 
 #define AB9540_MODEM_CTRL2_REG                 0x23
@@ -1324,25 +1328,6 @@ static int ab8500_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int ab8500_remove(struct platform_device *pdev)
-{
-       struct ab8500 *ab8500 = platform_get_drvdata(pdev);
-
-       if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
-                       ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
-               sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
-       else
-               sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
-
-       if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
-                       ab8500->chip_id >= AB8500_CUT2P0)
-               sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group);
-
-       mfd_remove_devices(ab8500->dev);
-
-       return 0;
-}
-
 static const struct platform_device_id ab8500_id[] = {
        { "ab8500-core", AB8500_VERSION_AB8500 },
        { "ab8505-i2c", AB8500_VERSION_AB8505 },
@@ -1354,9 +1339,9 @@ static const struct platform_device_id ab8500_id[] = {
 static struct platform_driver ab8500_core_driver = {
        .driver = {
                .name = "ab8500-core",
+               .suppress_bind_attrs = true,
        },
        .probe  = ab8500_probe,
-       .remove = ab8500_remove,
        .id_table = ab8500_id,
 };
 
@@ -1364,14 +1349,4 @@ static int __init ab8500_core_init(void)
 {
        return platform_driver_register(&ab8500_core_driver);
 }
-
-static void __exit ab8500_core_exit(void)
-{
-       platform_driver_unregister(&ab8500_core_driver);
-}
 core_initcall(ab8500_core_init);
-module_exit(ab8500_core_exit);
-
-MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
-MODULE_DESCRIPTION("AB8500 MFD core");
-MODULE_LICENSE("GPL v2");
index acf6c00b14b92c3bfb8f990df5778e5267c281ad..c1c815241e028375e3820e861251a8288bac730d 100644 (file)
@@ -74,7 +74,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
@@ -3234,33 +3234,16 @@ err:
        return -ENOMEM;
 }
 
-static int ab8500_debug_remove(struct platform_device *plf)
-{
-       debugfs_remove_recursive(ab8500_dir);
-
-       return 0;
-}
-
 static struct platform_driver ab8500_debug_driver = {
        .driver = {
                .name = "ab8500-debug",
+               .suppress_bind_attrs = true,
        },
        .probe  = ab8500_debug_probe,
-       .remove = ab8500_debug_remove
 };
 
 static int __init ab8500_debug_init(void)
 {
        return platform_driver_register(&ab8500_debug_driver);
 }
-
-static void __exit ab8500_debug_exit(void)
-{
-       platform_driver_unregister(&ab8500_debug_driver);
-}
 subsys_initcall(ab8500_debug_init);
-module_exit(ab8500_debug_exit);
-
-MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
-MODULE_DESCRIPTION("AB8500 DEBUG");
-MODULE_LICENSE("GPL v2");
index 97dcadc8fa8bfd898c16f788851f6b43a06b979e..f4e94869d6129a60d1da63cd851cbf0183ceb8fd 100644 (file)
@@ -5,9 +5,9 @@
  * Author: Arun R Murthy <arun.murthy@stericsson.com>
  * Author: Daniel Willerud <daniel.willerud@stericsson.com>
  * Author: Johan Palsson <johan.palsson@stericsson.com>
+ * Author: M'boumba Cedric Madianga
  */
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
@@ -1054,11 +1054,7 @@ static int __init ab8500_gpadc_init(void)
 {
        return platform_driver_register(&ab8500_gpadc_driver);
 }
-
-static void __exit ab8500_gpadc_exit(void)
-{
-       platform_driver_unregister(&ab8500_gpadc_driver);
-}
+subsys_initcall_sync(ab8500_gpadc_init);
 
 /**
  * ab8540_gpadc_get_otp() - returns OTP values
@@ -1077,14 +1073,3 @@ void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
        *ibat_l  = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
        *ibat_h  = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
 }
-
-subsys_initcall_sync(ab8500_gpadc_init);
-module_exit(ab8500_gpadc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Arun R Murthy");
-MODULE_AUTHOR("Daniel Willerud");
-MODULE_AUTHOR("Johan Palsson");
-MODULE_AUTHOR("M'boumba Cedric Madianga");
-MODULE_ALIAS("platform:ab8500_gpadc");
-MODULE_DESCRIPTION("AB8500 GPADC driver");
index 207cc497958a855c0abe012bbee749dfac650f93..80c0efa66ac13d1e5485cd9cee9461d79b43e594 100644 (file)
@@ -1,11 +1,14 @@
 /*
+ * AB8500 system control driver
+ *
  * Copyright (C) ST-Ericsson SA 2010
  * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
  * License terms: GNU General Public License (GPL) version 2
  */
 
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/reboot.h>
@@ -158,7 +161,3 @@ static int __init ab8500_sysctrl_init(void)
        return platform_driver_register(&ab8500_sysctrl_driver);
 }
 arch_initcall(ab8500_sysctrl_init);
-
-MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
-MODULE_DESCRIPTION("AB8500 system control driver");
-MODULE_LICENSE("GPL v2");
index fe418995108c6f75ea23908d97e8e6cefd6ecefe..0d3846a4767cba7479f68d7ab4badded7bb3019b 100644 (file)
@@ -8,7 +8,8 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/mfd/abx500.h>
 
 static LIST_HEAD(abx500_list);
@@ -150,7 +151,3 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
                return -ENOTSUPP;
 }
 EXPORT_SYMBOL(abx500_startup_irq_enabled);
-
-MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
-MODULE_DESCRIPTION("ABX500 core driver");
-MODULE_LICENSE("GPL");
index 41767f7239bbec98916da2de1ea1924b1b3beeba..b6d4bc63c42624388efc230355b2f0a0fd192f92 100644 (file)
@@ -1553,6 +1553,7 @@ EXPORT_SYMBOL_GPL(arizona_dev_init);
 
 int arizona_dev_exit(struct arizona *arizona)
 {
+       disable_irq(arizona->irq);
        pm_runtime_disable(arizona->dev);
 
        regulator_disable(arizona->dcvdd);
index 5e18d3c77582b02050da45db97ee87fc1777bab9..2e01975f042d5f63d0a29cdccb0000d0d1f358ad 100644 (file)
@@ -398,10 +398,10 @@ err_ctrlif:
 err_boot_done:
        free_irq(arizona->irq, arizona);
 err_main_irq:
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
                            arizona->irq_chip);
 err_aod:
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
                            arizona->aod_irq_chip);
 err:
        return ret;
@@ -413,9 +413,9 @@ int arizona_irq_exit(struct arizona *arizona)
                free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR),
                         arizona);
        free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
                            arizona->irq_chip);
-       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+       regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
                            arizona->aod_irq_chip);
        free_irq(arizona->irq, arizona);
 
index b1b865822c07e854050354d5c18b9010edeca6ca..d35a5fe6c950299787def746155a6c3fa61a99bc 100644 (file)
@@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
 
-/*
- * This is useless for OF-enabled devices, but it is needed by I2C subsystem
- */
 static const struct i2c_device_id axp20x_i2c_id[] = {
+       { "axp152", 0 },
+       { "axp202", 0 },
+       { "axp209", 0 },
+       { "axp221", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
index ba130be32e61363bef79298e5aa90c46bf8fb915..ed918de84238c33d83c9f60f26db069bec14a82d 100644 (file)
@@ -98,6 +98,7 @@ static const struct regmap_range axp22x_volatile_ranges[] = {
        regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
        regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
        regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
+       regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
        regmap_reg_range(AXP20X_FG_RES, AXP20X_FG_RES),
 };
 
@@ -135,6 +136,7 @@ static const struct regmap_range axp806_writeable_ranges[] = {
        regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL),
        regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN),
        regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
+       regmap_reg_range(AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT),
 };
 
 static const struct regmap_range axp806_volatile_ranges[] = {
@@ -305,7 +307,7 @@ static const struct regmap_config axp806_regmap_config = {
        .val_bits       = 8,
        .wr_table       = &axp806_writeable_table,
        .volatile_table = &axp806_volatile_table,
-       .max_register   = AXP806_VREF_TEMP_WARN_L,
+       .max_register   = AXP806_REG_ADDR_EXT,
        .cache_type     = REGCACHE_RBTREE,
 };
 
index 0d76d690176b4efd46c04246a5ccfff0a223b0c0..c572a35a934136f1c23190a2f58f5fc1bb9a8192 100644 (file)
@@ -67,7 +67,7 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri,
        /* Secondary I2C slave address is the base address with A(2) asserted */
        bcm590xx->i2c_sec = i2c_new_dummy(i2c_pri->adapter,
                                          i2c_pri->addr | BIT(2));
-       if (IS_ERR_OR_NULL(bcm590xx->i2c_sec)) {
+       if (!bcm590xx->i2c_sec) {
                dev_err(&i2c_pri->dev, "failed to add secondary I2C device\n");
                return -ENODEV;
        }
index f6b78aafdb557ac2f8f97b0b8392a0b682b528ad..c090974340ad38c2013fbf716f9be6576c960012 100644 (file)
@@ -292,6 +292,7 @@ static const struct reg_default cs47l24_reg_default[] = {
        { 0x00000502, 0x0000 },    /* R1282  - AIF1 Rx Pin Ctrl */
        { 0x00000503, 0x0000 },    /* R1283  - AIF1 Rate Ctrl */
        { 0x00000504, 0x0000 },    /* R1284  - AIF1 Format */
+       { 0x00000505, 0x0040 },    /* R1285  - AIF1 Tx BCLK Rate */
        { 0x00000506, 0x0040 },    /* R1286  - AIF1 Rx BCLK Rate */
        { 0x00000507, 0x1818 },    /* R1287  - AIF1 Frame Ctrl 1 */
        { 0x00000508, 0x1818 },    /* R1288  - AIF1 Frame Ctrl 2 */
@@ -318,6 +319,7 @@ static const struct reg_default cs47l24_reg_default[] = {
        { 0x00000542, 0x0000 },    /* R1346  - AIF2 Rx Pin Ctrl */
        { 0x00000543, 0x0000 },    /* R1347  - AIF2 Rate Ctrl */
        { 0x00000544, 0x0000 },    /* R1348  - AIF2 Format */
+       { 0x00000545, 0x0040 },    /* R1349  - AIF2 Tx BCLK Rate */
        { 0x00000546, 0x0040 },    /* R1350  - AIF2 Rx BCLK Rate */
        { 0x00000547, 0x1818 },    /* R1351  - AIF2 Frame Ctrl 1 */
        { 0x00000548, 0x1818 },    /* R1352  - AIF2 Frame Ctrl 2 */
@@ -340,6 +342,7 @@ static const struct reg_default cs47l24_reg_default[] = {
        { 0x00000582, 0x0000 },    /* R1410  - AIF3 Rx Pin Ctrl */
        { 0x00000583, 0x0000 },    /* R1411  - AIF3 Rate Ctrl */
        { 0x00000584, 0x0000 },    /* R1412  - AIF3 Format */
+       { 0x00000585, 0x0040 },    /* R1413  - AIF3 Tx BCLK Rate */
        { 0x00000586, 0x0040 },    /* R1414  - AIF3 Rx BCLK Rate */
        { 0x00000587, 0x1818 },    /* R1415  - AIF3 Frame Ctrl 1 */
        { 0x00000588, 0x1818 },    /* R1416  - AIF3 Frame Ctrl 2 */
@@ -923,6 +926,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_AIF1_RX_PIN_CTRL:
        case ARIZONA_AIF1_RATE_CTRL:
        case ARIZONA_AIF1_FORMAT:
+       case ARIZONA_AIF1_TX_BCLK_RATE:
        case ARIZONA_AIF1_RX_BCLK_RATE:
        case ARIZONA_AIF1_FRAME_CTRL_1:
        case ARIZONA_AIF1_FRAME_CTRL_2:
@@ -949,6 +953,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_AIF2_RX_PIN_CTRL:
        case ARIZONA_AIF2_RATE_CTRL:
        case ARIZONA_AIF2_FORMAT:
+       case ARIZONA_AIF2_TX_BCLK_RATE:
        case ARIZONA_AIF2_RX_BCLK_RATE:
        case ARIZONA_AIF2_FRAME_CTRL_1:
        case ARIZONA_AIF2_FRAME_CTRL_2:
@@ -971,6 +976,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_AIF3_RX_PIN_CTRL:
        case ARIZONA_AIF3_RATE_CTRL:
        case ARIZONA_AIF3_FORMAT:
+       case ARIZONA_AIF3_TX_BCLK_RATE:
        case ARIZONA_AIF3_RX_BCLK_RATE:
        case ARIZONA_AIF3_FRAME_CTRL_1:
        case ARIZONA_AIF3_FRAME_CTRL_2:
index dff2f19296b881801a00afde363a53acf939b633..4d0a5f38038a75f893c20fb07e944dfc04375e29 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/pcm.h>
 
 #include <linux/mfd/davinci_voicecodec.h>
+#include <mach/hardware.h>
 
 static const struct regmap_config davinci_vc_regmap = {
        .reg_bits = 32,
index 77b2675cf8f5df53b035ae1f3a373b7cb50754b8..ac430a396a89945b0cad1542db8a11b68b497fa5 100644 (file)
@@ -187,6 +187,7 @@ static const struct of_device_id mx25_tsadc_ids[] = {
        { .compatible = "fsl,imx25-tsadc" },
        { /* Sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mx25_tsadc_ids);
 
 static struct platform_driver mx25_tsadc_driver = {
        .driver = {
index 0fc62995695ba8e6912e85e62ac49a31a2cf8244..ba706adee38b551379e429f42b1de558d333c5b7 100644 (file)
@@ -169,6 +169,7 @@ static const struct of_device_id hi655x_pmic_match[] = {
        { .compatible = "hisilicon,hi655x-pmic", },
        {},
 };
+MODULE_DEVICE_TABLE(of, hi655x_pmic_match);
 
 static struct platform_driver hi655x_pmic_driver = {
        .driver = {
index 9ff243970e93ef1c025df40ca3e4474f59c371f5..78dbcf8b0befc90dea990644f24bf7b32e1c035e 100644 (file)
@@ -41,6 +41,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev,
 
        /* Probably it is enough to set this for iDMA capable devices only */
        pci_set_master(pdev);
+       pci_try_set_mwi(pdev);
 
        ret = intel_lpss_probe(&pdev->dev, info);
        if (ret)
index f9a8c5203873a2f8b6ac4a68e5582eddd69b3103..699c8c7c90528759c673192d14d804d9c46db89a 100644 (file)
@@ -42,6 +42,7 @@
 #define BXTWC_GPIOIRQ0         0x4E0B
 #define BXTWC_GPIOIRQ1         0x4E0C
 #define BXTWC_CRITIRQ          0x4E0D
+#define BXTWC_TMUIRQ           0x4FB6
 
 /* Interrupt MASK Registers */
 #define BXTWC_MIRQLVL1         0x4E0E
@@ -59,6 +60,7 @@
 #define BXTWC_MGPIO0IRQ                0x4E19
 #define BXTWC_MGPIO1IRQ                0x4E1A
 #define BXTWC_MCRITIRQ         0x4E1B
+#define BXTWC_MTMUIRQ          0x4FB7
 
 /* Whiskey Cove PMIC share same ACPI ID between different platforms */
 #define BROXTON_PMIC_WC_HRV    4
@@ -92,6 +94,7 @@ enum bxtwc_irqs_level2 {
        BXTWC_GPIO0_IRQ,
        BXTWC_GPIO1_IRQ,
        BXTWC_CRIT_IRQ,
+       BXTWC_TMU_IRQ,
 };
 
 static const struct regmap_irq bxtwc_regmap_irqs[] = {
@@ -120,6 +123,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
        REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03),
 };
 
+static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = {
+       REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06),
+};
+
 static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
        .name = "bxtwc_irq_chip",
        .status_base = BXTWC_IRQLVL1,
@@ -138,6 +145,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = {
        .num_regs = 10,
 };
 
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
+       .name = "bxtwc_irq_chip_tmu",
+       .status_base = BXTWC_TMUIRQ,
+       .mask_base = BXTWC_MTMUIRQ,
+       .irqs = bxtwc_regmap_irqs_tmu,
+       .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu),
+       .num_regs = 1,
+};
+
 static struct resource gpio_resources[] = {
        DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"),
        DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"),
@@ -166,6 +182,10 @@ static struct resource bcu_resources[] = {
        DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"),
 };
 
+static struct resource tmu_resources[] = {
+       DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"),
+};
+
 static struct mfd_cell bxt_wc_dev[] = {
        {
                .name = "bxt_wcove_gpadc",
@@ -192,6 +212,12 @@ static struct mfd_cell bxt_wc_dev[] = {
                .num_resources = ARRAY_SIZE(bcu_resources),
                .resources = bcu_resources,
        },
+       {
+               .name = "bxt_wcove_tmu",
+               .num_resources = ARRAY_SIZE(tmu_resources),
+               .resources = tmu_resources,
+       },
+
        {
                .name = "bxt_wcove_gpio",
                .num_resources = ARRAY_SIZE(gpio_resources),
@@ -402,6 +428,15 @@ static int bxtwc_probe(struct platform_device *pdev)
                goto err_irq_chip_level2;
        }
 
+       ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
+                                 IRQF_ONESHOT | IRQF_SHARED,
+                                 0, &bxtwc_regmap_irq_chip_tmu,
+                                 &pmic->irq_chip_data_tmu);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
+               goto err_irq_chip_tmu;
+       }
+
        ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
                              ARRAY_SIZE(bxt_wc_dev), NULL, 0,
                              NULL);
@@ -431,6 +466,8 @@ static int bxtwc_probe(struct platform_device *pdev)
 err_sysfs:
        mfd_remove_devices(&pdev->dev);
 err_mfd:
+       regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
+err_irq_chip_tmu:
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
 err_irq_chip_level2:
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
@@ -446,6 +483,7 @@ static int bxtwc_remove(struct platform_device *pdev)
        mfd_remove_devices(&pdev->dev);
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
        regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
+       regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
 
        return 0;
 }
@@ -481,7 +519,7 @@ static const struct acpi_device_id bxtwc_acpi_ids[] = {
        { "INT34D3", },
        { }
 };
-MODULE_DEVICE_TABLE(acpi, pmic_acpi_ids);
+MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids);
 
 static struct platform_driver bxtwc_driver = {
        .probe = bxtwc_probe,
index c8dee47b45d96f6e4aca9862cfaad7555de41082..1ef7575547e69d715972685fa46bdf10eb91f619 100644 (file)
@@ -493,6 +493,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_LPT] = {
                .name = "Lynx Point",
                .iTCO_version = 2,
+               .gpio_version = ICH_V5_GPIO,
        },
        [LPC_LPT_LP] = {
                .name = "Lynx Point_LP",
@@ -530,6 +531,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_9S] = {
                .name = "9 Series",
                .iTCO_version = 2,
+               .gpio_version = ICH_V5_GPIO,
        },
 };
 
index 8f8bacb67a15a4608de39efa80f30a0f7a550d02..ee9e9ea104447a47c7fd222a61e9f78d098bc121 100644 (file)
@@ -431,9 +431,6 @@ static void palmas_power_off(void)
        unsigned int addr;
        int ret, slave;
 
-       if (!palmas_dev)
-               return;
-
        slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
        addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL);
 
index 7f9620ec61e8f28f6954273c687f19e233d3c3d7..f08758f6b418f02fc1772770d321e9770b9d9435 100644 (file)
 #define        SSBI_REG_ADDR_IRQ_CONFIG        (SSBI_REG_ADDR_IRQ_BASE + 7)
 #define        SSBI_REG_ADDR_IRQ_RT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 8)
 
+#define        PM8821_SSBI_REG_ADDR_IRQ_BASE   0x100
+#define        PM8821_SSBI_REG_ADDR_IRQ_MASTER0 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0x30)
+#define        PM8821_SSBI_REG_ADDR_IRQ_MASTER1 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0xb0)
+#define        PM8821_SSBI_REG(m, b, offset) \
+                       ((m == 0) ? \
+                       (PM8821_SSBI_REG_ADDR_IRQ_MASTER0 + b + offset) : \
+                       (PM8821_SSBI_REG_ADDR_IRQ_MASTER1 + b + offset))
+#define        PM8821_SSBI_ADDR_IRQ_ROOT(m, b)         PM8821_SSBI_REG(m, b, 0x0)
+#define        PM8821_SSBI_ADDR_IRQ_CLEAR(m, b)        PM8821_SSBI_REG(m, b, 0x01)
+#define        PM8821_SSBI_ADDR_IRQ_MASK(m, b)         PM8821_SSBI_REG(m, b, 0x08)
+#define        PM8821_SSBI_ADDR_IRQ_RT_STATUS(m, b)    PM8821_SSBI_REG(m, b, 0x0f)
+
+#define        PM8821_BLOCKS_PER_MASTER        7
+
 #define        PM_IRQF_LVL_SEL                 0x01    /* level select */
 #define        PM_IRQF_MASK_FE                 0x02    /* mask falling edge */
 #define        PM_IRQF_MASK_RE                 0x04    /* mask rising edge */
@@ -54,6 +68,7 @@
 #define REG_HWREV_2            0x0E8  /* PMIC4 revision 2 */
 
 #define PM8XXX_NR_IRQS         256
+#define PM8821_NR_IRQS         112
 
 struct pm_irq_chip {
        struct regmap           *regmap;
@@ -65,6 +80,12 @@ struct pm_irq_chip {
        u8                      config[0];
 };
 
+struct pm_irq_data {
+       int num_irqs;
+       const struct irq_domain_ops  *irq_domain_ops;
+       void (*irq_handler)(struct irq_desc *desc);
+};
+
 static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
                                 unsigned int *ip)
 {
@@ -182,6 +203,78 @@ static void pm8xxx_irq_handler(struct irq_desc *desc)
        chained_irq_exit(irq_chip, desc);
 }
 
+static void pm8821_irq_block_handler(struct pm_irq_chip *chip,
+                                    int master, int block)
+{
+       int pmirq, irq, i, ret;
+       unsigned int bits;
+
+       ret = regmap_read(chip->regmap,
+                         PM8821_SSBI_ADDR_IRQ_ROOT(master, block), &bits);
+       if (ret) {
+               pr_err("Reading block %d failed ret=%d", block, ret);
+               return;
+       }
+
+       /* Convert block offset to global block number */
+       block += (master * PM8821_BLOCKS_PER_MASTER) - 1;
+
+       /* Check IRQ bits */
+       for (i = 0; i < 8; i++) {
+               if (bits & BIT(i)) {
+                       pmirq = block * 8 + i;
+                       irq = irq_find_mapping(chip->irqdomain, pmirq);
+                       generic_handle_irq(irq);
+               }
+       }
+}
+
+static inline void pm8821_irq_master_handler(struct pm_irq_chip *chip,
+                                            int master, u8 master_val)
+{
+       int block;
+
+       for (block = 1; block < 8; block++)
+               if (master_val & BIT(block))
+                       pm8821_irq_block_handler(chip, master, block);
+}
+
+static void pm8821_irq_handler(struct irq_desc *desc)
+{
+       struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
+       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+       unsigned int master;
+       int ret;
+
+       chained_irq_enter(irq_chip, desc);
+       ret = regmap_read(chip->regmap,
+                         PM8821_SSBI_REG_ADDR_IRQ_MASTER0, &master);
+       if (ret) {
+               pr_err("Failed to read master 0 ret=%d\n", ret);
+               goto done;
+       }
+
+       /* bits 1 through 7 marks the first 7 blocks in master 0 */
+       if (master & GENMASK(7, 1))
+               pm8821_irq_master_handler(chip, 0, master);
+
+       /* bit 0 marks if master 1 contains any bits */
+       if (!(master & BIT(0)))
+               goto done;
+
+       ret = regmap_read(chip->regmap,
+                         PM8821_SSBI_REG_ADDR_IRQ_MASTER1, &master);
+       if (ret) {
+               pr_err("Failed to read master 1 ret=%d\n", ret);
+               goto done;
+       }
+
+       pm8821_irq_master_handler(chip, 1, master);
+
+done:
+       chained_irq_exit(irq_chip, desc);
+}
+
 static void pm8xxx_irq_mask_ack(struct irq_data *d)
 {
        struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
@@ -299,6 +392,104 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
        .map = pm8xxx_irq_domain_map,
 };
 
+static void pm8821_irq_mask_ack(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       u8 block, master;
+       int irq_bit, rc;
+
+       block = pmirq / 8;
+       master = block / PM8821_BLOCKS_PER_MASTER;
+       irq_bit = pmirq % 8;
+       block %= PM8821_BLOCKS_PER_MASTER;
+
+       rc = regmap_update_bits(chip->regmap,
+                               PM8821_SSBI_ADDR_IRQ_MASK(master, block),
+                               BIT(irq_bit), BIT(irq_bit));
+       if (rc) {
+               pr_err("Failed to mask IRQ:%d rc=%d\n", pmirq, rc);
+               return;
+       }
+
+       rc = regmap_update_bits(chip->regmap,
+                               PM8821_SSBI_ADDR_IRQ_CLEAR(master, block),
+                               BIT(irq_bit), BIT(irq_bit));
+       if (rc)
+               pr_err("Failed to CLEAR IRQ:%d rc=%d\n", pmirq, rc);
+}
+
+static void pm8821_irq_unmask(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       int irq_bit, rc;
+       u8 block, master;
+
+       block = pmirq / 8;
+       master = block / PM8821_BLOCKS_PER_MASTER;
+       irq_bit = pmirq % 8;
+       block %= PM8821_BLOCKS_PER_MASTER;
+
+       rc = regmap_update_bits(chip->regmap,
+                               PM8821_SSBI_ADDR_IRQ_MASK(master, block),
+                               BIT(irq_bit), ~BIT(irq_bit));
+       if (rc)
+               pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc);
+
+}
+
+static int pm8821_irq_get_irqchip_state(struct irq_data *d,
+                                       enum irqchip_irq_state which,
+                                       bool *state)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       int rc, pmirq = irqd_to_hwirq(d);
+       u8 block, irq_bit, master;
+       unsigned int bits;
+
+       block = pmirq / 8;
+       master = block / PM8821_BLOCKS_PER_MASTER;
+       irq_bit = pmirq % 8;
+       block %= PM8821_BLOCKS_PER_MASTER;
+
+       rc = regmap_read(chip->regmap,
+               PM8821_SSBI_ADDR_IRQ_RT_STATUS(master, block), &bits);
+       if (rc) {
+               pr_err("Reading Status of IRQ %d failed rc=%d\n", pmirq, rc);
+               return rc;
+       }
+
+       *state = !!(bits & BIT(irq_bit));
+
+       return rc;
+}
+
+static struct irq_chip pm8821_irq_chip = {
+       .name           = "pm8821",
+       .irq_mask_ack   = pm8821_irq_mask_ack,
+       .irq_unmask     = pm8821_irq_unmask,
+       .irq_get_irqchip_state = pm8821_irq_get_irqchip_state,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+};
+
+static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                  irq_hw_number_t hwirq)
+{
+       struct pm_irq_chip *chip = d->host_data;
+
+       irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, chip);
+       irq_set_noprobe(irq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops pm8821_irq_domain_ops = {
+       .xlate = irq_domain_xlate_twocell,
+       .map = pm8821_irq_domain_map,
+};
+
 static const struct regmap_config ssbi_regmap_config = {
        .reg_bits = 16,
        .val_bits = 8,
@@ -308,22 +499,41 @@ static const struct regmap_config ssbi_regmap_config = {
        .reg_write = ssbi_reg_write
 };
 
+static const struct pm_irq_data pm8xxx_data = {
+       .num_irqs = PM8XXX_NR_IRQS,
+       .irq_domain_ops = &pm8xxx_irq_domain_ops,
+       .irq_handler = pm8xxx_irq_handler,
+};
+
+static const struct pm_irq_data pm8821_data = {
+       .num_irqs = PM8821_NR_IRQS,
+       .irq_domain_ops = &pm8821_irq_domain_ops,
+       .irq_handler = pm8821_irq_handler,
+};
+
 static const struct of_device_id pm8xxx_id_table[] = {
-       { .compatible = "qcom,pm8018", },
-       { .compatible = "qcom,pm8058", },
-       { .compatible = "qcom,pm8921", },
+       { .compatible = "qcom,pm8018", .data = &pm8xxx_data},
+       { .compatible = "qcom,pm8058", .data = &pm8xxx_data},
+       { .compatible = "qcom,pm8821", .data = &pm8821_data},
+       { .compatible = "qcom,pm8921", .data = &pm8xxx_data},
        { }
 };
 MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
 
 static int pm8xxx_probe(struct platform_device *pdev)
 {
+       const struct pm_irq_data *data;
        struct regmap *regmap;
        int irq, rc;
        unsigned int val;
        u32 rev;
        struct pm_irq_chip *chip;
-       unsigned int nirqs = PM8XXX_NR_IRQS;
+
+       data = of_device_get_match_data(&pdev->dev);
+       if (!data) {
+               dev_err(&pdev->dev, "No matching driver data found\n");
+               return -EINVAL;
+       }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
@@ -354,25 +564,26 @@ static int pm8xxx_probe(struct platform_device *pdev)
        rev |= val << BITS_PER_BYTE;
 
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
-                                       sizeof(chip->config[0]) * nirqs,
-                                       GFP_KERNEL);
+                           sizeof(chip->config[0]) * data->num_irqs,
+                           GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, chip);
        chip->regmap = regmap;
-       chip->num_irqs = nirqs;
+       chip->num_irqs = data->num_irqs;
        chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
        chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
        spin_lock_init(&chip->pm_irq_lock);
 
-       chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, nirqs,
-                                               &pm8xxx_irq_domain_ops,
+       chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
+                                               data->num_irqs,
+                                               data->irq_domain_ops,
                                                chip);
        if (!chip->irqdomain)
                return -ENODEV;
 
-       irq_set_chained_handler_and_data(irq, pm8xxx_irq_handler, chip);
+       irq_set_chained_handler_and_data(irq, data->irq_handler, chip);
        irq_set_irq_wake(irq, 1);
 
        rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
index 0f8acc5882a45261ffb5f90cffc23807d90b3412..2c9acdba7c2d36d5d5853bd3073a724d991e1426 100644 (file)
@@ -290,6 +290,24 @@ static void rk808_device_shutdown(void)
                dev_err(&rk808_i2c_client->dev, "power off error!\n");
 }
 
+static void rk818_device_shutdown(void)
+{
+       int ret;
+       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+
+       if (!rk808) {
+               dev_warn(&rk808_i2c_client->dev,
+                        "have no rk818, so do nothing here\n");
+               return;
+       }
+
+       ret = regmap_update_bits(rk808->regmap,
+                                RK818_DEVCTRL_REG,
+                                DEV_OFF, DEV_OFF);
+       if (ret)
+               dev_err(&rk808_i2c_client->dev, "power off error!\n");
+}
+
 static const struct of_device_id rk808_of_match[] = {
        { .compatible = "rockchip,rk808" },
        { .compatible = "rockchip,rk818" },
@@ -304,6 +322,7 @@ static int rk808_probe(struct i2c_client *client,
        struct rk808 *rk808;
        const struct rk808_reg_data *pre_init_reg;
        const struct mfd_cell *cells;
+       void (*pm_pwroff_fn)(void);
        int nr_pre_init_regs;
        int nr_cells;
        int pm_off = 0;
@@ -331,6 +350,7 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
                cells = rk808s;
                nr_cells = ARRAY_SIZE(rk808s);
+               pm_pwroff_fn = rk808_device_shutdown;
                break;
        case RK818_ID:
                rk808->regmap_cfg = &rk818_regmap_config;
@@ -339,6 +359,7 @@ static int rk808_probe(struct i2c_client *client,
                nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
                cells = rk818s;
                nr_cells = ARRAY_SIZE(rk818s);
+               pm_pwroff_fn = rk818_device_shutdown;
                break;
        default:
                dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
@@ -393,7 +414,7 @@ static int rk808_probe(struct i2c_client *client,
                                "rockchip,system-power-controller");
        if (pm_off && !pm_power_off) {
                rk808_i2c_client = client;
-               pm_power_off = rk808_device_shutdown;
+               pm_power_off = pm_pwroff_fn;
        }
 
        return 0;
index ee94080e1cbb704a6106b97d63fffe74e64a5daa..8131d1975745ec51a6219979f517827508c65497 100644 (file)
@@ -87,6 +87,7 @@ static int rn5t618_restart(struct notifier_block *this,
 static const struct of_device_id rn5t618_of_match[] = {
        { .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 },
        { .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 },
+       { .compatible = "ricoh,rc5t619", .data = (void *)RC5T619 },
        { }
 };
 MODULE_DEVICE_TABLE(of, rn5t618_of_match);
index c180b7533bbad7e953db2ff4c627cf7102a5fb62..e6a3d999a376a68877933b6e3d7b8403e299e1d4 100644 (file)
@@ -753,7 +753,7 @@ static int si476x_core_probe(struct i2c_client *client,
                                       ARRAY_SIZE(core->supplies),
                                       core->supplies);
        if (rval) {
-               dev_err(&client->dev, "Failet to gett all of the regulators\n");
+               dev_err(&client->dev, "Failed to get all of the regulators\n");
                goto free_gpio;
        }
 
diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c
new file mode 100644 (file)
index 0000000..9cfc881
--- /dev/null
@@ -0,0 +1,181 @@
+/* ADC MFD core driver for sunxi platforms
+ *
+ * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/sun4i-gpadc.h>
+
+#define ARCH_SUN4I_A10 0
+#define ARCH_SUN5I_A13 1
+#define ARCH_SUN6I_A31 2
+
+static struct resource adc_resources[] = {
+       DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_FIFO_DATA, "FIFO_DATA_PENDING"),
+       DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_TEMP_DATA, "TEMP_DATA_PENDING"),
+};
+
+static const struct regmap_irq sun4i_gpadc_regmap_irq[] = {
+       REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_FIFO_DATA, 0,
+                      SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN),
+       REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_TEMP_DATA, 0,
+                      SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN),
+};
+
+static const struct regmap_irq_chip sun4i_gpadc_regmap_irq_chip = {
+       .name = "sun4i_gpadc_irq_chip",
+       .status_base = SUN4I_GPADC_INT_FIFOS,
+       .ack_base = SUN4I_GPADC_INT_FIFOS,
+       .mask_base = SUN4I_GPADC_INT_FIFOC,
+       .init_ack_masked = true,
+       .mask_invert = true,
+       .irqs = sun4i_gpadc_regmap_irq,
+       .num_irqs = ARRAY_SIZE(sun4i_gpadc_regmap_irq),
+       .num_regs = 1,
+};
+
+static struct mfd_cell sun4i_gpadc_cells[] = {
+       {
+               .name   = "sun4i-a10-gpadc-iio",
+               .resources = adc_resources,
+               .num_resources = ARRAY_SIZE(adc_resources),
+       },
+       { .name = "iio_hwmon" }
+};
+
+static struct mfd_cell sun5i_gpadc_cells[] = {
+       {
+               .name   = "sun5i-a13-gpadc-iio",
+               .resources = adc_resources,
+               .num_resources = ARRAY_SIZE(adc_resources),
+       },
+       { .name = "iio_hwmon" },
+};
+
+static struct mfd_cell sun6i_gpadc_cells[] = {
+       {
+               .name   = "sun6i-a31-gpadc-iio",
+               .resources = adc_resources,
+               .num_resources = ARRAY_SIZE(adc_resources),
+       },
+       { .name = "iio_hwmon" },
+};
+
+static const struct regmap_config sun4i_gpadc_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .fast_io = true,
+};
+
+static const struct of_device_id sun4i_gpadc_of_match[] = {
+       {
+               .compatible = "allwinner,sun4i-a10-ts",
+               .data = (void *)ARCH_SUN4I_A10,
+       }, {
+               .compatible = "allwinner,sun5i-a13-ts",
+               .data = (void *)ARCH_SUN5I_A13,
+       }, {
+               .compatible = "allwinner,sun6i-a31-ts",
+               .data = (void *)ARCH_SUN6I_A31,
+       }, { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_match);
+
+static int sun4i_gpadc_probe(struct platform_device *pdev)
+{
+       struct sun4i_gpadc_dev *dev;
+       struct resource *mem;
+       const struct of_device_id *of_id;
+       const struct mfd_cell *cells;
+       unsigned int irq, size;
+       int ret;
+
+       of_id = of_match_node(sun4i_gpadc_of_match, pdev->dev.of_node);
+       if (!of_id)
+               return -EINVAL;
+
+       switch ((long)of_id->data) {
+       case ARCH_SUN4I_A10:
+               cells = sun4i_gpadc_cells;
+               size = ARRAY_SIZE(sun4i_gpadc_cells);
+               break;
+       case ARCH_SUN5I_A13:
+               cells = sun5i_gpadc_cells;
+               size = ARRAY_SIZE(sun5i_gpadc_cells);
+               break;
+       case ARCH_SUN6I_A31:
+               cells = sun6i_gpadc_cells;
+               size = ARRAY_SIZE(sun6i_gpadc_cells);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(dev->base))
+               return PTR_ERR(dev->base);
+
+       dev->dev = &pdev->dev;
+       dev_set_drvdata(dev->dev, dev);
+
+       dev->regmap = devm_regmap_init_mmio(dev->dev, dev->base,
+                                           &sun4i_gpadc_regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
+               dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
+       /* Disable all interrupts */
+       regmap_write(dev->regmap, SUN4I_GPADC_INT_FIFOC, 0);
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_regmap_add_irq_chip(&pdev->dev, dev->regmap, irq,
+                                      IRQF_ONESHOT, 0,
+                                      &sun4i_gpadc_regmap_irq_chip,
+                                      &dev->regmap_irqc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add irq chip: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_mfd_add_devices(dev->dev, 0, cells, size, NULL, 0, NULL);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add MFD devices: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct platform_driver sun4i_gpadc_driver = {
+       .driver = {
+               .name = "sun4i-gpadc",
+               .of_match_table = of_match_ptr(sun4i_gpadc_of_match),
+       },
+       .probe = sun4i_gpadc_probe,
+};
+
+module_platform_driver(sun4i_gpadc_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi platforms' GPADC MFD core driver");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
+MODULE_LICENSE("GPL v2");
index 274bf39968aaa1a9c9527fe0093cc7790d05f1f6..cc9e563f23aa6072d6160c9b33abe4c901bc1584 100644 (file)
@@ -53,7 +53,7 @@ int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
 EXPORT_SYMBOL_GPL(tc3589x_reg_read);
 
 /**
- * tc3589x_reg_read() - write a single TC3589x register
+ * tc3589x_reg_write() - write a single TC3589x register
  * @tc3589x:   Device to write to
  * @reg:       Register to read
  * @data:      Value to write
@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(tc3589x_block_write);
  * @tc3589x:   Device to write to
  * @reg:       Register to write
  * @mask:      Mask of bits to set
- * @values:    Value to set
+ * @val:       Value to set
  */
 int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
 {
index 9a4d8684dd32bd5beaf73547271bd2b1ee42431f..f769c7d4e335ac20da4db26ae5d7eb024d0b9987 100644 (file)
@@ -42,26 +42,6 @@ static struct resource pb_resources[] = {
        DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
 };
 
-struct tps65217_irq {
-       int mask;
-       int interrupt;
-};
-
-static const struct tps65217_irq tps65217_irqs[] = {
-       [TPS65217_IRQ_PB] = {
-               .mask = TPS65217_INT_PBM,
-               .interrupt = TPS65217_INT_PBI,
-       },
-       [TPS65217_IRQ_AC] = {
-               .mask = TPS65217_INT_ACM,
-               .interrupt = TPS65217_INT_ACI,
-       },
-       [TPS65217_IRQ_USB] = {
-               .mask = TPS65217_INT_USBM,
-               .interrupt = TPS65217_INT_USBI,
-       },
-};
-
 static void tps65217_irq_lock(struct irq_data *data)
 {
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
@@ -74,37 +54,32 @@ static void tps65217_irq_sync_unlock(struct irq_data *data)
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
        int ret;
 
-       ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
-                               TPS65217_PROTECT_NONE);
+       ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+                               tps->irq_mask, TPS65217_PROTECT_NONE);
        if (ret != 0)
                dev_err(tps->dev, "Failed to sync IRQ masks\n");
 
        mutex_unlock(&tps->irq_lock);
 }
 
-static inline const struct tps65217_irq *
-irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data)
-{
-       return &tps65217_irqs[data->hwirq];
-}
-
 static void tps65217_irq_enable(struct irq_data *data)
 {
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
-       const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+       u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
 
-       tps->irq_mask &= ~irq_data->mask;
+       tps->irq_mask &= ~mask;
 }
 
 static void tps65217_irq_disable(struct irq_data *data)
 {
        struct tps65217 *tps = irq_data_get_irq_chip_data(data);
-       const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
+       u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT;
 
-       tps->irq_mask |= irq_data->mask;
+       tps->irq_mask |= mask;
 }
 
 static struct irq_chip tps65217_irq_chip = {
+       .name                   = "tps65217",
        .irq_bus_lock           = tps65217_irq_lock,
        .irq_bus_sync_unlock    = tps65217_irq_sync_unlock,
        .irq_enable             = tps65217_irq_enable,
@@ -149,8 +124,8 @@ static irqreturn_t tps65217_irq_thread(int irq, void *data)
                return IRQ_NONE;
        }
 
-       for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) {
-               if (status & tps65217_irqs[i].interrupt) {
+       for (i = 0; i < TPS65217_NUM_IRQ; i++) {
+               if (status & BIT(i)) {
                        handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
                        handled = true;
                }
@@ -188,10 +163,9 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
        tps->irq = irq;
 
        /* Mask all interrupt sources */
-       tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
-                       | TPS65217_INT_ACM | TPS65217_INT_USBM);
-       tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
-                       TPS65217_PROTECT_NONE);
+       tps->irq_mask = TPS65217_INT_MASK;
+       tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK,
+                         TPS65217_INT_MASK, TPS65217_PROTECT_NONE);
 
        tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
                TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
@@ -209,6 +183,8 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq)
                return ret;
        }
 
+       enable_irq_wake(irq);
+
        return 0;
 }
 
@@ -424,6 +400,24 @@ static int tps65217_probe(struct i2c_client *client,
        return 0;
 }
 
+static int tps65217_remove(struct i2c_client *client)
+{
+       struct tps65217 *tps = i2c_get_clientdata(client);
+       unsigned int virq;
+       int i;
+
+       for (i = 0; i < TPS65217_NUM_IRQ; i++) {
+               virq = irq_find_mapping(tps->irq_domain, i);
+               if (virq)
+                       irq_dispose_mapping(virq);
+       }
+
+       irq_domain_remove(tps->irq_domain);
+       tps->irq_domain = NULL;
+
+       return 0;
+}
+
 static const struct i2c_device_id tps65217_id_table[] = {
        {"tps65217", TPS65217},
        { /* sentinel */ }
@@ -437,6 +431,7 @@ static struct i2c_driver tps65217_driver = {
        },
        .id_table       = tps65217_id_table,
        .probe          = tps65217_probe,
+       .remove         = tps65217_remove,
 };
 
 static int __init tps65217_init(void)
index ba610adbdbff33503f65cea2ceda2273f95fc2fb..13834a0d28172fe5334f0385571fafb34cc21248 100644 (file)
 
 #define TPS65218_PASSWORD_REGS_UNLOCK   0x7D
 
-/**
- * tps65218_reg_read: Read a single tps65218 register.
- *
- * @tps: Device to read from.
- * @reg: Register to read.
- * @val: Contians the value
- */
-int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
-                       unsigned int *val)
-{
-       return regmap_read(tps->regmap, reg, val);
-}
-EXPORT_SYMBOL_GPL(tps65218_reg_read);
+static const struct mfd_cell tps65218_cells[] = {
+       {
+               .name = "tps65218-pwrbutton",
+               .of_compatible = "ti,tps65218-pwrbutton",
+       },
+       {
+               .name = "tps65218-gpio",
+               .of_compatible = "ti,tps65218-gpio",
+       },
+       { .name = "tps65218-regulator", },
+};
 
 /**
  * tps65218_reg_write: Write a single tps65218 register.
@@ -93,7 +91,7 @@ static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg,
        int ret;
        unsigned int data;
 
-       ret = tps65218_reg_read(tps, reg, &data);
+       ret = regmap_read(tps->regmap, reg, &data);
        if (ret) {
                dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
                return ret;
@@ -251,7 +249,7 @@ static int tps65218_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
-       ret = tps65218_reg_read(tps, TPS65218_REG_CHIPID, &chipid);
+       ret = regmap_read(tps->regmap, TPS65218_REG_CHIPID, &chipid);
        if (ret) {
                dev_err(tps->dev, "Failed to read chipid: %d\n", ret);
                return ret;
@@ -259,8 +257,10 @@ static int tps65218_probe(struct i2c_client *client,
 
        tps->rev = chipid & TPS65218_CHIPID_REV_MASK;
 
-       ret = of_platform_populate(client->dev.of_node, NULL, NULL,
-                                  &client->dev);
+       ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65218_cells,
+                             ARRAY_SIZE(tps65218_cells), NULL, 0,
+                             regmap_irq_get_domain(tps->irq_data));
+
        if (ret < 0)
                goto err_irq;
 
index a88cfa80dbc4816f3c236d4c4282f59af09893e0..f33567bc428d1f7a2a6e00ef1b962ea8851d417c 100644 (file)
@@ -77,6 +77,23 @@ static struct regmap_irq_chip tps65912_irq_chip = {
        .init_ack_masked = true,
 };
 
+static const struct regmap_range tps65912_yes_ranges[] = {
+       regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5),
+};
+
+static const struct regmap_access_table tps65912_volatile_table = {
+       .yes_ranges = tps65912_yes_ranges,
+       .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges),
+};
+
+const struct regmap_config tps65912_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_table = &tps65912_volatile_table,
+};
+EXPORT_SYMBOL_GPL(tps65912_regmap_config);
+
 int tps65912_device_init(struct tps65912 *tps)
 {
        int ret;
index ab8b23b5bd22b085d5fbd1a16338cd36a82db729..853113d97c1e8311e812625f79be82a862e71704 100644 (file)
@@ -244,752 +244,752 @@ const struct regmap_irq_chip wm5102_irq = {
 };
 
 static const struct reg_default wm5102_reg_default[] = {
-       { 0x00000008, 0x0019 },   /* R8     - Ctrl IF SPI CFG 1 */ 
-       { 0x00000009, 0x0001 },   /* R9     - Ctrl IF I2C1 CFG 1 */ 
-       { 0x00000020, 0x0000 },   /* R32    - Tone Generator 1 */ 
-       { 0x00000021, 0x1000 },   /* R33    - Tone Generator 2 */ 
-       { 0x00000022, 0x0000 },   /* R34    - Tone Generator 3 */ 
-       { 0x00000023, 0x1000 },   /* R35    - Tone Generator 4 */ 
-       { 0x00000024, 0x0000 },   /* R36    - Tone Generator 5 */ 
-       { 0x00000030, 0x0000 },   /* R48    - PWM Drive 1 */ 
-       { 0x00000031, 0x0100 },   /* R49    - PWM Drive 2 */ 
-       { 0x00000032, 0x0100 },   /* R50    - PWM Drive 3 */ 
-       { 0x00000040, 0x0000 },   /* R64    - Wake control */ 
-       { 0x00000041, 0x0000 },   /* R65    - Sequence control */ 
-       { 0x00000061, 0x01FF },   /* R97    - Sample Rate Sequence Select 1 */ 
-       { 0x00000062, 0x01FF },   /* R98    - Sample Rate Sequence Select 2 */ 
-       { 0x00000063, 0x01FF },   /* R99    - Sample Rate Sequence Select 3 */ 
-       { 0x00000064, 0x01FF },   /* R100   - Sample Rate Sequence Select 4 */ 
+       { 0x00000008, 0x0019 },   /* R8     - Ctrl IF SPI CFG 1 */
+       { 0x00000009, 0x0001 },   /* R9     - Ctrl IF I2C1 CFG 1 */
+       { 0x00000020, 0x0000 },   /* R32    - Tone Generator 1 */
+       { 0x00000021, 0x1000 },   /* R33    - Tone Generator 2 */
+       { 0x00000022, 0x0000 },   /* R34    - Tone Generator 3 */
+       { 0x00000023, 0x1000 },   /* R35    - Tone Generator 4 */
+       { 0x00000024, 0x0000 },   /* R36    - Tone Generator 5 */
+       { 0x00000030, 0x0000 },   /* R48    - PWM Drive 1 */
+       { 0x00000031, 0x0100 },   /* R49    - PWM Drive 2 */
+       { 0x00000032, 0x0100 },   /* R50    - PWM Drive 3 */
+       { 0x00000040, 0x0000 },   /* R64    - Wake control */
+       { 0x00000041, 0x0000 },   /* R65    - Sequence control */
+       { 0x00000061, 0x01FF },   /* R97    - Sample Rate Sequence Select 1 */
+       { 0x00000062, 0x01FF },   /* R98    - Sample Rate Sequence Select 2 */
+       { 0x00000063, 0x01FF },   /* R99    - Sample Rate Sequence Select 3 */
+       { 0x00000064, 0x01FF },   /* R100   - Sample Rate Sequence Select 4 */
        { 0x00000066, 0x01FF },   /* R102   - Always On Triggers Sequence Select 1 */
        { 0x00000067, 0x01FF },   /* R103   - Always On Triggers Sequence Select 2 */
        { 0x00000068, 0x01FF },   /* R104   - Always On Triggers Sequence Select 3 */
        { 0x00000069, 0x01FF },   /* R105   - Always On Triggers Sequence Select 4 */
        { 0x0000006A, 0x01FF },   /* R106   - Always On Triggers Sequence Select 5 */
        { 0x0000006B, 0x01FF },   /* R107   - Always On Triggers Sequence Select 6 */
-       { 0x00000070, 0x0000 },   /* R112   - Comfort Noise Generator */ 
-       { 0x00000090, 0x0000 },   /* R144   - Haptics Control 1 */ 
-       { 0x00000091, 0x7FFF },   /* R145   - Haptics Control 2 */ 
-       { 0x00000092, 0x0000 },   /* R146   - Haptics phase 1 intensity */ 
-       { 0x00000093, 0x0000 },   /* R147   - Haptics phase 1 duration */ 
-       { 0x00000094, 0x0000 },   /* R148   - Haptics phase 2 intensity */ 
-       { 0x00000095, 0x0000 },   /* R149   - Haptics phase 2 duration */ 
-       { 0x00000096, 0x0000 },   /* R150   - Haptics phase 3 intensity */ 
-       { 0x00000097, 0x0000 },   /* R151   - Haptics phase 3 duration */ 
+       { 0x00000070, 0x0000 },   /* R112   - Comfort Noise Generator */
+       { 0x00000090, 0x0000 },   /* R144   - Haptics Control 1 */
+       { 0x00000091, 0x7FFF },   /* R145   - Haptics Control 2 */
+       { 0x00000092, 0x0000 },   /* R146   - Haptics phase 1 intensity */
+       { 0x00000093, 0x0000 },   /* R147   - Haptics phase 1 duration */
+       { 0x00000094, 0x0000 },   /* R148   - Haptics phase 2 intensity */
+       { 0x00000095, 0x0000 },   /* R149   - Haptics phase 2 duration */
+       { 0x00000096, 0x0000 },   /* R150   - Haptics phase 3 intensity */
+       { 0x00000097, 0x0000 },   /* R151   - Haptics phase 3 duration */
        { 0x00000100, 0x0002 },   /* R256   - Clock 32k 1 */
-       { 0x00000101, 0x0304 },   /* R257   - System Clock 1 */ 
-       { 0x00000102, 0x0011 },   /* R258   - Sample rate 1 */ 
-       { 0x00000103, 0x0011 },   /* R259   - Sample rate 2 */ 
-       { 0x00000104, 0x0011 },   /* R260   - Sample rate 3 */ 
-       { 0x00000112, 0x0305 },   /* R274   - Async clock 1 */ 
-       { 0x00000113, 0x0011 },   /* R275   - Async sample rate 1 */ 
+       { 0x00000101, 0x0304 },   /* R257   - System Clock 1 */
+       { 0x00000102, 0x0011 },   /* R258   - Sample rate 1 */
+       { 0x00000103, 0x0011 },   /* R259   - Sample rate 2 */
+       { 0x00000104, 0x0011 },   /* R260   - Sample rate 3 */
+       { 0x00000112, 0x0305 },   /* R274   - Async clock 1 */
+       { 0x00000113, 0x0011 },   /* R275   - Async sample rate 1 */
        { 0x00000114, 0x0011 },   /* R276   - Async sample rate 2 */
-       { 0x00000149, 0x0000 },   /* R329   - Output system clock */ 
-       { 0x0000014A, 0x0000 },   /* R330   - Output async clock */ 
-       { 0x00000152, 0x0000 },   /* R338   - Rate Estimator 1 */ 
-       { 0x00000153, 0x0000 },   /* R339   - Rate Estimator 2 */ 
-       { 0x00000154, 0x0000 },   /* R340   - Rate Estimator 3 */ 
-       { 0x00000155, 0x0000 },   /* R341   - Rate Estimator 4 */ 
-       { 0x00000156, 0x0000 },   /* R342   - Rate Estimator 5 */ 
-       { 0x00000161, 0x0000 },   /* R353   - Dynamic Frequency Scaling 1 */ 
+       { 0x00000149, 0x0000 },   /* R329   - Output system clock */
+       { 0x0000014A, 0x0000 },   /* R330   - Output async clock */
+       { 0x00000152, 0x0000 },   /* R338   - Rate Estimator 1 */
+       { 0x00000153, 0x0000 },   /* R339   - Rate Estimator 2 */
+       { 0x00000154, 0x0000 },   /* R340   - Rate Estimator 3 */
+       { 0x00000155, 0x0000 },   /* R341   - Rate Estimator 4 */
+       { 0x00000156, 0x0000 },   /* R342   - Rate Estimator 5 */
+       { 0x00000161, 0x0000 },   /* R353   - Dynamic Frequency Scaling 1 */
        { 0x00000171, 0x0000 },   /* R369   - FLL1 Control 1 */
-       { 0x00000172, 0x0008 },   /* R370   - FLL1 Control 2 */ 
-       { 0x00000173, 0x0018 },   /* R371   - FLL1 Control 3 */ 
-       { 0x00000174, 0x007D },   /* R372   - FLL1 Control 4 */ 
-       { 0x00000175, 0x0004 },   /* R373   - FLL1 Control 5 */ 
-       { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
+       { 0x00000172, 0x0008 },   /* R370   - FLL1 Control 2 */
+       { 0x00000173, 0x0018 },   /* R371   - FLL1 Control 3 */
+       { 0x00000174, 0x007D },   /* R372   - FLL1 Control 4 */
+       { 0x00000175, 0x0004 },   /* R373   - FLL1 Control 5 */
+       { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */
        { 0x00000179, 0x0000 },   /* R377   - FLL1 Control 7 */
-       { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
-       { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
-       { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
-       { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */ 
-       { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */ 
-       { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */ 
+       { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */
+       { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */
+       { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */
+       { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */
+       { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */
+       { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */
        { 0x00000187, 0x0001 },   /* R391   - FLL1 Synchroniser 7 */
-       { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */ 
-       { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */ 
-       { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */ 
-       { 0x00000192, 0x0008 },   /* R402   - FLL2 Control 2 */ 
-       { 0x00000193, 0x0018 },   /* R403   - FLL2 Control 3 */ 
-       { 0x00000194, 0x007D },   /* R404   - FLL2 Control 4 */ 
-       { 0x00000195, 0x0004 },   /* R405   - FLL2 Control 5 */ 
-       { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
+       { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */
+       { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */
+       { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */
+       { 0x00000192, 0x0008 },   /* R402   - FLL2 Control 2 */
+       { 0x00000193, 0x0018 },   /* R403   - FLL2 Control 3 */
+       { 0x00000194, 0x007D },   /* R404   - FLL2 Control 4 */
+       { 0x00000195, 0x0004 },   /* R405   - FLL2 Control 5 */
+       { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */
        { 0x00000199, 0x0000 },   /* R409   - FLL2 Control 7 */
-       { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
-       { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
-       { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
-       { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */ 
-       { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */ 
-       { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */ 
+       { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */
+       { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */
+       { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */
+       { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */
+       { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */
+       { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */
        { 0x000001A7, 0x0001 },   /* R423   - FLL2 Synchroniser 7 */
-       { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */ 
-       { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */ 
-       { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */ 
-       { 0x00000210, 0x00D4 },   /* R528   - LDO1 Control 1 */ 
+       { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */
+       { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */
+       { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */
+       { 0x00000210, 0x00D4 },   /* R528   - LDO1 Control 1 */
        { 0x00000212, 0x0000 },   /* R530   - LDO1 Control 2 */
-       { 0x00000213, 0x0344 },   /* R531   - LDO2 Control 1 */ 
-       { 0x00000218, 0x01A6 },   /* R536   - Mic Bias Ctrl 1 */ 
-       { 0x00000219, 0x01A6 },   /* R537   - Mic Bias Ctrl 2 */ 
-       { 0x0000021A, 0x01A6 },   /* R538   - Mic Bias Ctrl 3 */ 
-       { 0x00000293, 0x0000 },   /* R659   - Accessory Detect Mode 1 */ 
-       { 0x0000029B, 0x0020 },   /* R667   - Headphone Detect 1 */ 
+       { 0x00000213, 0x0344 },   /* R531   - LDO2 Control 1 */
+       { 0x00000218, 0x01A6 },   /* R536   - Mic Bias Ctrl 1 */
+       { 0x00000219, 0x01A6 },   /* R537   - Mic Bias Ctrl 2 */
+       { 0x0000021A, 0x01A6 },   /* R538   - Mic Bias Ctrl 3 */
+       { 0x00000293, 0x0000 },   /* R659   - Accessory Detect Mode 1 */
+       { 0x0000029B, 0x0020 },   /* R667   - Headphone Detect 1 */
        { 0x000002A2, 0x0000 },   /* R674   - Micd clamp control */
-       { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */ 
-       { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */ 
+       { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */
+       { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */
        { 0x000002A6, 0x3737 },   /* R678   - Mic Detect Level 1 */
        { 0x000002A7, 0x2C37 },   /* R679   - Mic Detect Level 2 */
        { 0x000002A8, 0x1422 },   /* R680   - Mic Detect Level 3 */
        { 0x000002A9, 0x030A },   /* R681   - Mic Detect Level 4 */
-       { 0x000002C3, 0x0000 },   /* R707   - Mic noise mix control 1 */ 
-       { 0x000002CB, 0x0000 },   /* R715   - Isolation control */ 
-       { 0x000002D3, 0x0000 },   /* R723   - Jack detect analogue */ 
-       { 0x00000300, 0x0000 },   /* R768   - Input Enables */ 
-       { 0x00000308, 0x0000 },   /* R776   - Input Rate */ 
-       { 0x00000309, 0x0022 },   /* R777   - Input Volume Ramp */ 
-       { 0x00000310, 0x2080 },   /* R784   - IN1L Control */ 
-       { 0x00000311, 0x0180 },   /* R785   - ADC Digital Volume 1L */ 
-       { 0x00000312, 0x0000 },   /* R786   - DMIC1L Control */ 
-       { 0x00000314, 0x0080 },   /* R788   - IN1R Control */ 
-       { 0x00000315, 0x0180 },   /* R789   - ADC Digital Volume 1R */ 
-       { 0x00000316, 0x0000 },   /* R790   - DMIC1R Control */ 
-       { 0x00000318, 0x2080 },   /* R792   - IN2L Control */ 
-       { 0x00000319, 0x0180 },   /* R793   - ADC Digital Volume 2L */ 
-       { 0x0000031A, 0x0000 },   /* R794   - DMIC2L Control */ 
-       { 0x0000031C, 0x0080 },   /* R796   - IN2R Control */ 
-       { 0x0000031D, 0x0180 },   /* R797   - ADC Digital Volume 2R */ 
-       { 0x0000031E, 0x0000 },   /* R798   - DMIC2R Control */ 
-       { 0x00000320, 0x2080 },   /* R800   - IN3L Control */ 
-       { 0x00000321, 0x0180 },   /* R801   - ADC Digital Volume 3L */ 
-       { 0x00000322, 0x0000 },   /* R802   - DMIC3L Control */ 
-       { 0x00000324, 0x0080 },   /* R804   - IN3R Control */ 
-       { 0x00000325, 0x0180 },   /* R805   - ADC Digital Volume 3R */ 
-       { 0x00000326, 0x0000 },   /* R806   - DMIC3R Control */ 
-       { 0x00000400, 0x0000 },   /* R1024  - Output Enables 1 */ 
-       { 0x00000408, 0x0000 },   /* R1032  - Output Rate 1 */ 
-       { 0x00000409, 0x0022 },   /* R1033  - Output Volume Ramp */ 
+       { 0x000002C3, 0x0000 },   /* R707   - Mic noise mix control 1 */
+       { 0x000002CB, 0x0000 },   /* R715   - Isolation control */
+       { 0x000002D3, 0x0000 },   /* R723   - Jack detect analogue */
+       { 0x00000300, 0x0000 },   /* R768   - Input Enables */
+       { 0x00000308, 0x0000 },   /* R776   - Input Rate */
+       { 0x00000309, 0x0022 },   /* R777   - Input Volume Ramp */
+       { 0x00000310, 0x2080 },   /* R784   - IN1L Control */
+       { 0x00000311, 0x0180 },   /* R785   - ADC Digital Volume 1L */
+       { 0x00000312, 0x0000 },   /* R786   - DMIC1L Control */
+       { 0x00000314, 0x0080 },   /* R788   - IN1R Control */
+       { 0x00000315, 0x0180 },   /* R789   - ADC Digital Volume 1R */
+       { 0x00000316, 0x0000 },   /* R790   - DMIC1R Control */
+       { 0x00000318, 0x2080 },   /* R792   - IN2L Control */
+       { 0x00000319, 0x0180 },   /* R793   - ADC Digital Volume 2L */
+       { 0x0000031A, 0x0000 },   /* R794   - DMIC2L Control */
+       { 0x0000031C, 0x0080 },   /* R796   - IN2R Control */
+       { 0x0000031D, 0x0180 },   /* R797   - ADC Digital Volume 2R */
+       { 0x0000031E, 0x0000 },   /* R798   - DMIC2R Control */
+       { 0x00000320, 0x2080 },   /* R800   - IN3L Control */
+       { 0x00000321, 0x0180 },   /* R801   - ADC Digital Volume 3L */
+       { 0x00000322, 0x0000 },   /* R802   - DMIC3L Control */
+       { 0x00000324, 0x0080 },   /* R804   - IN3R Control */
+       { 0x00000325, 0x0180 },   /* R805   - ADC Digital Volume 3R */
+       { 0x00000326, 0x0000 },   /* R806   - DMIC3R Control */
+       { 0x00000400, 0x0000 },   /* R1024  - Output Enables 1 */
+       { 0x00000408, 0x0000 },   /* R1032  - Output Rate 1 */
+       { 0x00000409, 0x0022 },   /* R1033  - Output Volume Ramp */
        { 0x00000410, 0x6080 },   /* R1040  - Output Path Config 1L */
-       { 0x00000411, 0x0180 },   /* R1041  - DAC Digital Volume 1L */ 
+       { 0x00000411, 0x0180 },   /* R1041  - DAC Digital Volume 1L */
        { 0x00000412, 0x0081 },   /* R1042  - DAC Volume Limit 1L */
-       { 0x00000413, 0x0001 },   /* R1043  - Noise Gate Select 1L */ 
-       { 0x00000414, 0x0080 },   /* R1044  - Output Path Config 1R */ 
-       { 0x00000415, 0x0180 },   /* R1045  - DAC Digital Volume 1R */ 
+       { 0x00000413, 0x0001 },   /* R1043  - Noise Gate Select 1L */
+       { 0x00000414, 0x0080 },   /* R1044  - Output Path Config 1R */
+       { 0x00000415, 0x0180 },   /* R1045  - DAC Digital Volume 1R */
        { 0x00000416, 0x0081 },   /* R1046  - DAC Volume Limit 1R */
-       { 0x00000417, 0x0002 },   /* R1047  - Noise Gate Select 1R */ 
+       { 0x00000417, 0x0002 },   /* R1047  - Noise Gate Select 1R */
        { 0x00000418, 0xA080 },   /* R1048  - Output Path Config 2L */
-       { 0x00000419, 0x0180 },   /* R1049  - DAC Digital Volume 2L */ 
+       { 0x00000419, 0x0180 },   /* R1049  - DAC Digital Volume 2L */
        { 0x0000041A, 0x0081 },   /* R1050  - DAC Volume Limit 2L */
-       { 0x0000041B, 0x0004 },   /* R1051  - Noise Gate Select 2L */ 
-       { 0x0000041C, 0x0080 },   /* R1052  - Output Path Config 2R */ 
-       { 0x0000041D, 0x0180 },   /* R1053  - DAC Digital Volume 2R */ 
+       { 0x0000041B, 0x0004 },   /* R1051  - Noise Gate Select 2L */
+       { 0x0000041C, 0x0080 },   /* R1052  - Output Path Config 2R */
+       { 0x0000041D, 0x0180 },   /* R1053  - DAC Digital Volume 2R */
        { 0x0000041E, 0x0081 },   /* R1054  - DAC Volume Limit 2R */
-       { 0x0000041F, 0x0008 },   /* R1055  - Noise Gate Select 2R */ 
+       { 0x0000041F, 0x0008 },   /* R1055  - Noise Gate Select 2R */
        { 0x00000420, 0xA080 },   /* R1056  - Output Path Config 3L */
-       { 0x00000421, 0x0180 },   /* R1057  - DAC Digital Volume 3L */ 
+       { 0x00000421, 0x0180 },   /* R1057  - DAC Digital Volume 3L */
        { 0x00000422, 0x0081 },   /* R1058  - DAC Volume Limit 3L */
-       { 0x00000423, 0x0010 },   /* R1059  - Noise Gate Select 3L */ 
+       { 0x00000423, 0x0010 },   /* R1059  - Noise Gate Select 3L */
        { 0x00000428, 0xE000 },   /* R1064  - Output Path Config 4L */
-       { 0x00000429, 0x0180 },   /* R1065  - DAC Digital Volume 4L */ 
+       { 0x00000429, 0x0180 },   /* R1065  - DAC Digital Volume 4L */
        { 0x0000042A, 0x0081 },   /* R1066  - Out Volume 4L */
-       { 0x0000042B, 0x0040 },   /* R1067  - Noise Gate Select 4L */ 
-       { 0x0000042D, 0x0180 },   /* R1069  - DAC Digital Volume 4R */ 
+       { 0x0000042B, 0x0040 },   /* R1067  - Noise Gate Select 4L */
+       { 0x0000042D, 0x0180 },   /* R1069  - DAC Digital Volume 4R */
        { 0x0000042E, 0x0081 },   /* R1070  - Out Volume 4R */
-       { 0x0000042F, 0x0080 },   /* R1071  - Noise Gate Select 4R */ 
-       { 0x00000430, 0x0000 },   /* R1072  - Output Path Config 5L */ 
-       { 0x00000431, 0x0180 },   /* R1073  - DAC Digital Volume 5L */ 
+       { 0x0000042F, 0x0080 },   /* R1071  - Noise Gate Select 4R */
+       { 0x00000430, 0x0000 },   /* R1072  - Output Path Config 5L */
+       { 0x00000431, 0x0180 },   /* R1073  - DAC Digital Volume 5L */
        { 0x00000432, 0x0081 },   /* R1074  - DAC Volume Limit 5L */
-       { 0x00000433, 0x0100 },   /* R1075  - Noise Gate Select 5L */ 
-       { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */ 
+       { 0x00000433, 0x0100 },   /* R1075  - Noise Gate Select 5L */
+       { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */
        { 0x00000436, 0x0081 },   /* R1078  - DAC Volume Limit 5R */
        { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */
        { 0x00000440, 0x0FFF },   /* R1088  - DRE Enable */
        { 0x00000442, 0x3F0A },   /* R1090  - DRE Control 2 */
        { 0x00000443, 0xDC1F },   /* R1090  - DRE Control 3 */
-       { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */ 
+       { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */
        { 0x00000458, 0x000B },   /* R1112  - Noise Gate Control */
-       { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */ 
-       { 0x00000491, 0x0000 },   /* R1169  - PDM SPK1 CTRL 2 */ 
-       { 0x00000500, 0x000C },   /* R1280  - AIF1 BCLK Ctrl */ 
-       { 0x00000501, 0x0008 },   /* R1281  - AIF1 Tx Pin Ctrl */ 
-       { 0x00000502, 0x0000 },   /* R1282  - AIF1 Rx Pin Ctrl */ 
-       { 0x00000503, 0x0000 },   /* R1283  - AIF1 Rate Ctrl */ 
-       { 0x00000504, 0x0000 },   /* R1284  - AIF1 Format */ 
-       { 0x00000505, 0x0040 },   /* R1285  - AIF1 Tx BCLK Rate */ 
-       { 0x00000506, 0x0040 },   /* R1286  - AIF1 Rx BCLK Rate */ 
-       { 0x00000507, 0x1818 },   /* R1287  - AIF1 Frame Ctrl 1 */ 
-       { 0x00000508, 0x1818 },   /* R1288  - AIF1 Frame Ctrl 2 */ 
-       { 0x00000509, 0x0000 },   /* R1289  - AIF1 Frame Ctrl 3 */ 
-       { 0x0000050A, 0x0001 },   /* R1290  - AIF1 Frame Ctrl 4 */ 
-       { 0x0000050B, 0x0002 },   /* R1291  - AIF1 Frame Ctrl 5 */ 
-       { 0x0000050C, 0x0003 },   /* R1292  - AIF1 Frame Ctrl 6 */ 
-       { 0x0000050D, 0x0004 },   /* R1293  - AIF1 Frame Ctrl 7 */ 
-       { 0x0000050E, 0x0005 },   /* R1294  - AIF1 Frame Ctrl 8 */ 
-       { 0x0000050F, 0x0006 },   /* R1295  - AIF1 Frame Ctrl 9 */ 
-       { 0x00000510, 0x0007 },   /* R1296  - AIF1 Frame Ctrl 10 */ 
-       { 0x00000511, 0x0000 },   /* R1297  - AIF1 Frame Ctrl 11 */ 
-       { 0x00000512, 0x0001 },   /* R1298  - AIF1 Frame Ctrl 12 */ 
-       { 0x00000513, 0x0002 },   /* R1299  - AIF1 Frame Ctrl 13 */ 
-       { 0x00000514, 0x0003 },   /* R1300  - AIF1 Frame Ctrl 14 */ 
-       { 0x00000515, 0x0004 },   /* R1301  - AIF1 Frame Ctrl 15 */ 
-       { 0x00000516, 0x0005 },   /* R1302  - AIF1 Frame Ctrl 16 */ 
-       { 0x00000517, 0x0006 },   /* R1303  - AIF1 Frame Ctrl 17 */ 
-       { 0x00000518, 0x0007 },   /* R1304  - AIF1 Frame Ctrl 18 */ 
-       { 0x00000519, 0x0000 },   /* R1305  - AIF1 Tx Enables */ 
-       { 0x0000051A, 0x0000 },   /* R1306  - AIF1 Rx Enables */ 
-       { 0x00000540, 0x000C },   /* R1344  - AIF2 BCLK Ctrl */ 
-       { 0x00000541, 0x0008 },   /* R1345  - AIF2 Tx Pin Ctrl */ 
-       { 0x00000542, 0x0000 },   /* R1346  - AIF2 Rx Pin Ctrl */ 
-       { 0x00000543, 0x0000 },   /* R1347  - AIF2 Rate Ctrl */ 
-       { 0x00000544, 0x0000 },   /* R1348  - AIF2 Format */ 
-       { 0x00000545, 0x0040 },   /* R1349  - AIF2 Tx BCLK Rate */ 
-       { 0x00000546, 0x0040 },   /* R1350  - AIF2 Rx BCLK Rate */ 
-       { 0x00000547, 0x1818 },   /* R1351  - AIF2 Frame Ctrl 1 */ 
-       { 0x00000548, 0x1818 },   /* R1352  - AIF2 Frame Ctrl 2 */ 
-       { 0x00000549, 0x0000 },   /* R1353  - AIF2 Frame Ctrl 3 */ 
-       { 0x0000054A, 0x0001 },   /* R1354  - AIF2 Frame Ctrl 4 */ 
-       { 0x00000551, 0x0000 },   /* R1361  - AIF2 Frame Ctrl 11 */ 
-       { 0x00000552, 0x0001 },   /* R1362  - AIF2 Frame Ctrl 12 */ 
-       { 0x00000559, 0x0000 },   /* R1369  - AIF2 Tx Enables */ 
-       { 0x0000055A, 0x0000 },   /* R1370  - AIF2 Rx Enables */ 
-       { 0x00000580, 0x000C },   /* R1408  - AIF3 BCLK Ctrl */ 
-       { 0x00000581, 0x0008 },   /* R1409  - AIF3 Tx Pin Ctrl */ 
-       { 0x00000582, 0x0000 },   /* R1410  - AIF3 Rx Pin Ctrl */ 
-       { 0x00000583, 0x0000 },   /* R1411  - AIF3 Rate Ctrl */ 
-       { 0x00000584, 0x0000 },   /* R1412  - AIF3 Format */ 
-       { 0x00000585, 0x0040 },   /* R1413  - AIF3 Tx BCLK Rate */ 
-       { 0x00000586, 0x0040 },   /* R1414  - AIF3 Rx BCLK Rate */ 
-       { 0x00000587, 0x1818 },   /* R1415  - AIF3 Frame Ctrl 1 */ 
-       { 0x00000588, 0x1818 },   /* R1416  - AIF3 Frame Ctrl 2 */ 
-       { 0x00000589, 0x0000 },   /* R1417  - AIF3 Frame Ctrl 3 */ 
-       { 0x0000058A, 0x0001 },   /* R1418  - AIF3 Frame Ctrl 4 */ 
-       { 0x00000591, 0x0000 },   /* R1425  - AIF3 Frame Ctrl 11 */ 
-       { 0x00000592, 0x0001 },   /* R1426  - AIF3 Frame Ctrl 12 */ 
-       { 0x00000599, 0x0000 },   /* R1433  - AIF3 Tx Enables */ 
-       { 0x0000059A, 0x0000 },   /* R1434  - AIF3 Rx Enables */ 
-       { 0x000005E3, 0x0004 },   /* R1507  - SLIMbus Framer Ref Gear */ 
-       { 0x000005E5, 0x0000 },   /* R1509  - SLIMbus Rates 1 */ 
-       { 0x000005E6, 0x0000 },   /* R1510  - SLIMbus Rates 2 */ 
-       { 0x000005E7, 0x0000 },   /* R1511  - SLIMbus Rates 3 */ 
-       { 0x000005E8, 0x0000 },   /* R1512  - SLIMbus Rates 4 */ 
-       { 0x000005E9, 0x0000 },   /* R1513  - SLIMbus Rates 5 */ 
-       { 0x000005EA, 0x0000 },   /* R1514  - SLIMbus Rates 6 */ 
-       { 0x000005EB, 0x0000 },   /* R1515  - SLIMbus Rates 7 */ 
-       { 0x000005EC, 0x0000 },   /* R1516  - SLIMbus Rates 8 */ 
-       { 0x000005F5, 0x0000 },   /* R1525  - SLIMbus RX Channel Enable */ 
-       { 0x000005F6, 0x0000 },   /* R1526  - SLIMbus TX Channel Enable */ 
-       { 0x00000640, 0x0000 },   /* R1600  - PWM1MIX Input 1 Source */ 
-       { 0x00000641, 0x0080 },   /* R1601  - PWM1MIX Input 1 Volume */ 
-       { 0x00000642, 0x0000 },   /* R1602  - PWM1MIX Input 2 Source */ 
-       { 0x00000643, 0x0080 },   /* R1603  - PWM1MIX Input 2 Volume */ 
-       { 0x00000644, 0x0000 },   /* R1604  - PWM1MIX Input 3 Source */ 
-       { 0x00000645, 0x0080 },   /* R1605  - PWM1MIX Input 3 Volume */ 
-       { 0x00000646, 0x0000 },   /* R1606  - PWM1MIX Input 4 Source */ 
-       { 0x00000647, 0x0080 },   /* R1607  - PWM1MIX Input 4 Volume */ 
-       { 0x00000648, 0x0000 },   /* R1608  - PWM2MIX Input 1 Source */ 
-       { 0x00000649, 0x0080 },   /* R1609  - PWM2MIX Input 1 Volume */ 
-       { 0x0000064A, 0x0000 },   /* R1610  - PWM2MIX Input 2 Source */ 
-       { 0x0000064B, 0x0080 },   /* R1611  - PWM2MIX Input 2 Volume */ 
-       { 0x0000064C, 0x0000 },   /* R1612  - PWM2MIX Input 3 Source */ 
-       { 0x0000064D, 0x0080 },   /* R1613  - PWM2MIX Input 3 Volume */ 
-       { 0x0000064E, 0x0000 },   /* R1614  - PWM2MIX Input 4 Source */ 
-       { 0x0000064F, 0x0080 },   /* R1615  - PWM2MIX Input 4 Volume */ 
-       { 0x00000660, 0x0000 },   /* R1632  - MICMIX Input 1 Source */ 
-       { 0x00000661, 0x0080 },   /* R1633  - MICMIX Input 1 Volume */ 
-       { 0x00000662, 0x0000 },   /* R1634  - MICMIX Input 2 Source */ 
-       { 0x00000663, 0x0080 },   /* R1635  - MICMIX Input 2 Volume */ 
-       { 0x00000664, 0x0000 },   /* R1636  - MICMIX Input 3 Source */ 
-       { 0x00000665, 0x0080 },   /* R1637  - MICMIX Input 3 Volume */ 
-       { 0x00000666, 0x0000 },   /* R1638  - MICMIX Input 4 Source */ 
-       { 0x00000667, 0x0080 },   /* R1639  - MICMIX Input 4 Volume */ 
-       { 0x00000668, 0x0000 },   /* R1640  - NOISEMIX Input 1 Source */ 
-       { 0x00000669, 0x0080 },   /* R1641  - NOISEMIX Input 1 Volume */ 
-       { 0x0000066A, 0x0000 },   /* R1642  - NOISEMIX Input 2 Source */ 
-       { 0x0000066B, 0x0080 },   /* R1643  - NOISEMIX Input 2 Volume */ 
-       { 0x0000066C, 0x0000 },   /* R1644  - NOISEMIX Input 3 Source */ 
-       { 0x0000066D, 0x0080 },   /* R1645  - NOISEMIX Input 3 Volume */ 
-       { 0x0000066E, 0x0000 },   /* R1646  - NOISEMIX Input 4 Source */ 
-       { 0x0000066F, 0x0080 },   /* R1647  - NOISEMIX Input 4 Volume */ 
-       { 0x00000680, 0x0000 },   /* R1664  - OUT1LMIX Input 1 Source */ 
-       { 0x00000681, 0x0080 },   /* R1665  - OUT1LMIX Input 1 Volume */ 
-       { 0x00000682, 0x0000 },   /* R1666  - OUT1LMIX Input 2 Source */ 
-       { 0x00000683, 0x0080 },   /* R1667  - OUT1LMIX Input 2 Volume */ 
-       { 0x00000684, 0x0000 },   /* R1668  - OUT1LMIX Input 3 Source */ 
-       { 0x00000685, 0x0080 },   /* R1669  - OUT1LMIX Input 3 Volume */ 
-       { 0x00000686, 0x0000 },   /* R1670  - OUT1LMIX Input 4 Source */ 
-       { 0x00000687, 0x0080 },   /* R1671  - OUT1LMIX Input 4 Volume */ 
-       { 0x00000688, 0x0000 },   /* R1672  - OUT1RMIX Input 1 Source */ 
-       { 0x00000689, 0x0080 },   /* R1673  - OUT1RMIX Input 1 Volume */ 
-       { 0x0000068A, 0x0000 },   /* R1674  - OUT1RMIX Input 2 Source */ 
-       { 0x0000068B, 0x0080 },   /* R1675  - OUT1RMIX Input 2 Volume */ 
-       { 0x0000068C, 0x0000 },   /* R1676  - OUT1RMIX Input 3 Source */ 
-       { 0x0000068D, 0x0080 },   /* R1677  - OUT1RMIX Input 3 Volume */ 
-       { 0x0000068E, 0x0000 },   /* R1678  - OUT1RMIX Input 4 Source */ 
-       { 0x0000068F, 0x0080 },   /* R1679  - OUT1RMIX Input 4 Volume */ 
-       { 0x00000690, 0x0000 },   /* R1680  - OUT2LMIX Input 1 Source */ 
-       { 0x00000691, 0x0080 },   /* R1681  - OUT2LMIX Input 1 Volume */ 
-       { 0x00000692, 0x0000 },   /* R1682  - OUT2LMIX Input 2 Source */ 
-       { 0x00000693, 0x0080 },   /* R1683  - OUT2LMIX Input 2 Volume */ 
-       { 0x00000694, 0x0000 },   /* R1684  - OUT2LMIX Input 3 Source */ 
-       { 0x00000695, 0x0080 },   /* R1685  - OUT2LMIX Input 3 Volume */ 
-       { 0x00000696, 0x0000 },   /* R1686  - OUT2LMIX Input 4 Source */ 
-       { 0x00000697, 0x0080 },   /* R1687  - OUT2LMIX Input 4 Volume */ 
-       { 0x00000698, 0x0000 },   /* R1688  - OUT2RMIX Input 1 Source */ 
-       { 0x00000699, 0x0080 },   /* R1689  - OUT2RMIX Input 1 Volume */ 
-       { 0x0000069A, 0x0000 },   /* R1690  - OUT2RMIX Input 2 Source */ 
-       { 0x0000069B, 0x0080 },   /* R1691  - OUT2RMIX Input 2 Volume */ 
-       { 0x0000069C, 0x0000 },   /* R1692  - OUT2RMIX Input 3 Source */ 
-       { 0x0000069D, 0x0080 },   /* R1693  - OUT2RMIX Input 3 Volume */ 
-       { 0x0000069E, 0x0000 },   /* R1694  - OUT2RMIX Input 4 Source */ 
-       { 0x0000069F, 0x0080 },   /* R1695  - OUT2RMIX Input 4 Volume */ 
-       { 0x000006A0, 0x0000 },   /* R1696  - OUT3LMIX Input 1 Source */ 
-       { 0x000006A1, 0x0080 },   /* R1697  - OUT3LMIX Input 1 Volume */ 
-       { 0x000006A2, 0x0000 },   /* R1698  - OUT3LMIX Input 2 Source */ 
-       { 0x000006A3, 0x0080 },   /* R1699  - OUT3LMIX Input 2 Volume */ 
-       { 0x000006A4, 0x0000 },   /* R1700  - OUT3LMIX Input 3 Source */ 
-       { 0x000006A5, 0x0080 },   /* R1701  - OUT3LMIX Input 3 Volume */ 
-       { 0x000006A6, 0x0000 },   /* R1702  - OUT3LMIX Input 4 Source */ 
-       { 0x000006A7, 0x0080 },   /* R1703  - OUT3LMIX Input 4 Volume */ 
-       { 0x000006B0, 0x0000 },   /* R1712  - OUT4LMIX Input 1 Source */ 
-       { 0x000006B1, 0x0080 },   /* R1713  - OUT4LMIX Input 1 Volume */ 
-       { 0x000006B2, 0x0000 },   /* R1714  - OUT4LMIX Input 2 Source */ 
-       { 0x000006B3, 0x0080 },   /* R1715  - OUT4LMIX Input 2 Volume */ 
-       { 0x000006B4, 0x0000 },   /* R1716  - OUT4LMIX Input 3 Source */ 
-       { 0x000006B5, 0x0080 },   /* R1717  - OUT4LMIX Input 3 Volume */ 
-       { 0x000006B6, 0x0000 },   /* R1718  - OUT4LMIX Input 4 Source */ 
-       { 0x000006B7, 0x0080 },   /* R1719  - OUT4LMIX Input 4 Volume */ 
-       { 0x000006B8, 0x0000 },   /* R1720  - OUT4RMIX Input 1 Source */ 
-       { 0x000006B9, 0x0080 },   /* R1721  - OUT4RMIX Input 1 Volume */ 
-       { 0x000006BA, 0x0000 },   /* R1722  - OUT4RMIX Input 2 Source */ 
-       { 0x000006BB, 0x0080 },   /* R1723  - OUT4RMIX Input 2 Volume */ 
-       { 0x000006BC, 0x0000 },   /* R1724  - OUT4RMIX Input 3 Source */ 
-       { 0x000006BD, 0x0080 },   /* R1725  - OUT4RMIX Input 3 Volume */ 
-       { 0x000006BE, 0x0000 },   /* R1726  - OUT4RMIX Input 4 Source */ 
-       { 0x000006BF, 0x0080 },   /* R1727  - OUT4RMIX Input 4 Volume */ 
-       { 0x000006C0, 0x0000 },   /* R1728  - OUT5LMIX Input 1 Source */ 
-       { 0x000006C1, 0x0080 },   /* R1729  - OUT5LMIX Input 1 Volume */ 
-       { 0x000006C2, 0x0000 },   /* R1730  - OUT5LMIX Input 2 Source */ 
-       { 0x000006C3, 0x0080 },   /* R1731  - OUT5LMIX Input 2 Volume */ 
-       { 0x000006C4, 0x0000 },   /* R1732  - OUT5LMIX Input 3 Source */ 
-       { 0x000006C5, 0x0080 },   /* R1733  - OUT5LMIX Input 3 Volume */ 
-       { 0x000006C6, 0x0000 },   /* R1734  - OUT5LMIX Input 4 Source */ 
-       { 0x000006C7, 0x0080 },   /* R1735  - OUT5LMIX Input 4 Volume */ 
-       { 0x000006C8, 0x0000 },   /* R1736  - OUT5RMIX Input 1 Source */ 
-       { 0x000006C9, 0x0080 },   /* R1737  - OUT5RMIX Input 1 Volume */ 
-       { 0x000006CA, 0x0000 },   /* R1738  - OUT5RMIX Input 2 Source */ 
-       { 0x000006CB, 0x0080 },   /* R1739  - OUT5RMIX Input 2 Volume */ 
-       { 0x000006CC, 0x0000 },   /* R1740  - OUT5RMIX Input 3 Source */ 
-       { 0x000006CD, 0x0080 },   /* R1741  - OUT5RMIX Input 3 Volume */ 
-       { 0x000006CE, 0x0000 },   /* R1742  - OUT5RMIX Input 4 Source */ 
-       { 0x000006CF, 0x0080 },   /* R1743  - OUT5RMIX Input 4 Volume */ 
-       { 0x00000700, 0x0000 },   /* R1792  - AIF1TX1MIX Input 1 Source */ 
-       { 0x00000701, 0x0080 },   /* R1793  - AIF1TX1MIX Input 1 Volume */ 
-       { 0x00000702, 0x0000 },   /* R1794  - AIF1TX1MIX Input 2 Source */ 
-       { 0x00000703, 0x0080 },   /* R1795  - AIF1TX1MIX Input 2 Volume */ 
-       { 0x00000704, 0x0000 },   /* R1796  - AIF1TX1MIX Input 3 Source */ 
-       { 0x00000705, 0x0080 },   /* R1797  - AIF1TX1MIX Input 3 Volume */ 
-       { 0x00000706, 0x0000 },   /* R1798  - AIF1TX1MIX Input 4 Source */ 
-       { 0x00000707, 0x0080 },   /* R1799  - AIF1TX1MIX Input 4 Volume */ 
-       { 0x00000708, 0x0000 },   /* R1800  - AIF1TX2MIX Input 1 Source */ 
-       { 0x00000709, 0x0080 },   /* R1801  - AIF1TX2MIX Input 1 Volume */ 
-       { 0x0000070A, 0x0000 },   /* R1802  - AIF1TX2MIX Input 2 Source */ 
-       { 0x0000070B, 0x0080 },   /* R1803  - AIF1TX2MIX Input 2 Volume */ 
-       { 0x0000070C, 0x0000 },   /* R1804  - AIF1TX2MIX Input 3 Source */ 
-       { 0x0000070D, 0x0080 },   /* R1805  - AIF1TX2MIX Input 3 Volume */ 
-       { 0x0000070E, 0x0000 },   /* R1806  - AIF1TX2MIX Input 4 Source */ 
-       { 0x0000070F, 0x0080 },   /* R1807  - AIF1TX2MIX Input 4 Volume */ 
-       { 0x00000710, 0x0000 },   /* R1808  - AIF1TX3MIX Input 1 Source */ 
-       { 0x00000711, 0x0080 },   /* R1809  - AIF1TX3MIX Input 1 Volume */ 
-       { 0x00000712, 0x0000 },   /* R1810  - AIF1TX3MIX Input 2 Source */ 
-       { 0x00000713, 0x0080 },   /* R1811  - AIF1TX3MIX Input 2 Volume */ 
-       { 0x00000714, 0x0000 },   /* R1812  - AIF1TX3MIX Input 3 Source */ 
-       { 0x00000715, 0x0080 },   /* R1813  - AIF1TX3MIX Input 3 Volume */ 
-       { 0x00000716, 0x0000 },   /* R1814  - AIF1TX3MIX Input 4 Source */ 
-       { 0x00000717, 0x0080 },   /* R1815  - AIF1TX3MIX Input 4 Volume */ 
-       { 0x00000718, 0x0000 },   /* R1816  - AIF1TX4MIX Input 1 Source */ 
-       { 0x00000719, 0x0080 },   /* R1817  - AIF1TX4MIX Input 1 Volume */ 
-       { 0x0000071A, 0x0000 },   /* R1818  - AIF1TX4MIX Input 2 Source */ 
-       { 0x0000071B, 0x0080 },   /* R1819  - AIF1TX4MIX Input 2 Volume */ 
-       { 0x0000071C, 0x0000 },   /* R1820  - AIF1TX4MIX Input 3 Source */ 
-       { 0x0000071D, 0x0080 },   /* R1821  - AIF1TX4MIX Input 3 Volume */ 
-       { 0x0000071E, 0x0000 },   /* R1822  - AIF1TX4MIX Input 4 Source */ 
-       { 0x0000071F, 0x0080 },   /* R1823  - AIF1TX4MIX Input 4 Volume */ 
-       { 0x00000720, 0x0000 },   /* R1824  - AIF1TX5MIX Input 1 Source */ 
-       { 0x00000721, 0x0080 },   /* R1825  - AIF1TX5MIX Input 1 Volume */ 
-       { 0x00000722, 0x0000 },   /* R1826  - AIF1TX5MIX Input 2 Source */ 
-       { 0x00000723, 0x0080 },   /* R1827  - AIF1TX5MIX Input 2 Volume */ 
-       { 0x00000724, 0x0000 },   /* R1828  - AIF1TX5MIX Input 3 Source */ 
-       { 0x00000725, 0x0080 },   /* R1829  - AIF1TX5MIX Input 3 Volume */ 
-       { 0x00000726, 0x0000 },   /* R1830  - AIF1TX5MIX Input 4 Source */ 
-       { 0x00000727, 0x0080 },   /* R1831  - AIF1TX5MIX Input 4 Volume */ 
-       { 0x00000728, 0x0000 },   /* R1832  - AIF1TX6MIX Input 1 Source */ 
-       { 0x00000729, 0x0080 },   /* R1833  - AIF1TX6MIX Input 1 Volume */ 
-       { 0x0000072A, 0x0000 },   /* R1834  - AIF1TX6MIX Input 2 Source */ 
-       { 0x0000072B, 0x0080 },   /* R1835  - AIF1TX6MIX Input 2 Volume */ 
-       { 0x0000072C, 0x0000 },   /* R1836  - AIF1TX6MIX Input 3 Source */ 
-       { 0x0000072D, 0x0080 },   /* R1837  - AIF1TX6MIX Input 3 Volume */ 
-       { 0x0000072E, 0x0000 },   /* R1838  - AIF1TX6MIX Input 4 Source */ 
-       { 0x0000072F, 0x0080 },   /* R1839  - AIF1TX6MIX Input 4 Volume */ 
-       { 0x00000730, 0x0000 },   /* R1840  - AIF1TX7MIX Input 1 Source */ 
-       { 0x00000731, 0x0080 },   /* R1841  - AIF1TX7MIX Input 1 Volume */ 
-       { 0x00000732, 0x0000 },   /* R1842  - AIF1TX7MIX Input 2 Source */ 
-       { 0x00000733, 0x0080 },   /* R1843  - AIF1TX7MIX Input 2 Volume */ 
-       { 0x00000734, 0x0000 },   /* R1844  - AIF1TX7MIX Input 3 Source */ 
-       { 0x00000735, 0x0080 },   /* R1845  - AIF1TX7MIX Input 3 Volume */ 
-       { 0x00000736, 0x0000 },   /* R1846  - AIF1TX7MIX Input 4 Source */ 
-       { 0x00000737, 0x0080 },   /* R1847  - AIF1TX7MIX Input 4 Volume */ 
-       { 0x00000738, 0x0000 },   /* R1848  - AIF1TX8MIX Input 1 Source */ 
-       { 0x00000739, 0x0080 },   /* R1849  - AIF1TX8MIX Input 1 Volume */ 
-       { 0x0000073A, 0x0000 },   /* R1850  - AIF1TX8MIX Input 2 Source */ 
-       { 0x0000073B, 0x0080 },   /* R1851  - AIF1TX8MIX Input 2 Volume */ 
-       { 0x0000073C, 0x0000 },   /* R1852  - AIF1TX8MIX Input 3 Source */ 
-       { 0x0000073D, 0x0080 },   /* R1853  - AIF1TX8MIX Input 3 Volume */ 
-       { 0x0000073E, 0x0000 },   /* R1854  - AIF1TX8MIX Input 4 Source */ 
-       { 0x0000073F, 0x0080 },   /* R1855  - AIF1TX8MIX Input 4 Volume */ 
-       { 0x00000740, 0x0000 },   /* R1856  - AIF2TX1MIX Input 1 Source */ 
-       { 0x00000741, 0x0080 },   /* R1857  - AIF2TX1MIX Input 1 Volume */ 
-       { 0x00000742, 0x0000 },   /* R1858  - AIF2TX1MIX Input 2 Source */ 
-       { 0x00000743, 0x0080 },   /* R1859  - AIF2TX1MIX Input 2 Volume */ 
-       { 0x00000744, 0x0000 },   /* R1860  - AIF2TX1MIX Input 3 Source */ 
-       { 0x00000745, 0x0080 },   /* R1861  - AIF2TX1MIX Input 3 Volume */ 
-       { 0x00000746, 0x0000 },   /* R1862  - AIF2TX1MIX Input 4 Source */ 
-       { 0x00000747, 0x0080 },   /* R1863  - AIF2TX1MIX Input 4 Volume */ 
-       { 0x00000748, 0x0000 },   /* R1864  - AIF2TX2MIX Input 1 Source */ 
-       { 0x00000749, 0x0080 },   /* R1865  - AIF2TX2MIX Input 1 Volume */ 
-       { 0x0000074A, 0x0000 },   /* R1866  - AIF2TX2MIX Input 2 Source */ 
-       { 0x0000074B, 0x0080 },   /* R1867  - AIF2TX2MIX Input 2 Volume */ 
-       { 0x0000074C, 0x0000 },   /* R1868  - AIF2TX2MIX Input 3 Source */ 
-       { 0x0000074D, 0x0080 },   /* R1869  - AIF2TX2MIX Input 3 Volume */ 
-       { 0x0000074E, 0x0000 },   /* R1870  - AIF2TX2MIX Input 4 Source */ 
-       { 0x0000074F, 0x0080 },   /* R1871  - AIF2TX2MIX Input 4 Volume */ 
-       { 0x00000780, 0x0000 },   /* R1920  - AIF3TX1MIX Input 1 Source */ 
-       { 0x00000781, 0x0080 },   /* R1921  - AIF3TX1MIX Input 1 Volume */ 
-       { 0x00000782, 0x0000 },   /* R1922  - AIF3TX1MIX Input 2 Source */ 
-       { 0x00000783, 0x0080 },   /* R1923  - AIF3TX1MIX Input 2 Volume */ 
-       { 0x00000784, 0x0000 },   /* R1924  - AIF3TX1MIX Input 3 Source */ 
-       { 0x00000785, 0x0080 },   /* R1925  - AIF3TX1MIX Input 3 Volume */ 
-       { 0x00000786, 0x0000 },   /* R1926  - AIF3TX1MIX Input 4 Source */ 
-       { 0x00000787, 0x0080 },   /* R1927  - AIF3TX1MIX Input 4 Volume */ 
-       { 0x00000788, 0x0000 },   /* R1928  - AIF3TX2MIX Input 1 Source */ 
-       { 0x00000789, 0x0080 },   /* R1929  - AIF3TX2MIX Input 1 Volume */ 
-       { 0x0000078A, 0x0000 },   /* R1930  - AIF3TX2MIX Input 2 Source */ 
-       { 0x0000078B, 0x0080 },   /* R1931  - AIF3TX2MIX Input 2 Volume */ 
-       { 0x0000078C, 0x0000 },   /* R1932  - AIF3TX2MIX Input 3 Source */ 
-       { 0x0000078D, 0x0080 },   /* R1933  - AIF3TX2MIX Input 3 Volume */ 
-       { 0x0000078E, 0x0000 },   /* R1934  - AIF3TX2MIX Input 4 Source */ 
-       { 0x0000078F, 0x0080 },   /* R1935  - AIF3TX2MIX Input 4 Volume */ 
-       { 0x000007C0, 0x0000 },   /* R1984  - SLIMTX1MIX Input 1 Source */ 
-       { 0x000007C1, 0x0080 },   /* R1985  - SLIMTX1MIX Input 1 Volume */ 
-       { 0x000007C2, 0x0000 },   /* R1986  - SLIMTX1MIX Input 2 Source */ 
-       { 0x000007C3, 0x0080 },   /* R1987  - SLIMTX1MIX Input 2 Volume */ 
-       { 0x000007C4, 0x0000 },   /* R1988  - SLIMTX1MIX Input 3 Source */ 
-       { 0x000007C5, 0x0080 },   /* R1989  - SLIMTX1MIX Input 3 Volume */ 
-       { 0x000007C6, 0x0000 },   /* R1990  - SLIMTX1MIX Input 4 Source */ 
-       { 0x000007C7, 0x0080 },   /* R1991  - SLIMTX1MIX Input 4 Volume */ 
-       { 0x000007C8, 0x0000 },   /* R1992  - SLIMTX2MIX Input 1 Source */ 
-       { 0x000007C9, 0x0080 },   /* R1993  - SLIMTX2MIX Input 1 Volume */ 
-       { 0x000007CA, 0x0000 },   /* R1994  - SLIMTX2MIX Input 2 Source */ 
-       { 0x000007CB, 0x0080 },   /* R1995  - SLIMTX2MIX Input 2 Volume */ 
-       { 0x000007CC, 0x0000 },   /* R1996  - SLIMTX2MIX Input 3 Source */ 
-       { 0x000007CD, 0x0080 },   /* R1997  - SLIMTX2MIX Input 3 Volume */ 
-       { 0x000007CE, 0x0000 },   /* R1998  - SLIMTX2MIX Input 4 Source */ 
-       { 0x000007CF, 0x0080 },   /* R1999  - SLIMTX2MIX Input 4 Volume */ 
-       { 0x000007D0, 0x0000 },   /* R2000  - SLIMTX3MIX Input 1 Source */ 
-       { 0x000007D1, 0x0080 },   /* R2001  - SLIMTX3MIX Input 1 Volume */ 
-       { 0x000007D2, 0x0000 },   /* R2002  - SLIMTX3MIX Input 2 Source */ 
-       { 0x000007D3, 0x0080 },   /* R2003  - SLIMTX3MIX Input 2 Volume */ 
-       { 0x000007D4, 0x0000 },   /* R2004  - SLIMTX3MIX Input 3 Source */ 
-       { 0x000007D5, 0x0080 },   /* R2005  - SLIMTX3MIX Input 3 Volume */ 
-       { 0x000007D6, 0x0000 },   /* R2006  - SLIMTX3MIX Input 4 Source */ 
-       { 0x000007D7, 0x0080 },   /* R2007  - SLIMTX3MIX Input 4 Volume */ 
-       { 0x000007D8, 0x0000 },   /* R2008  - SLIMTX4MIX Input 1 Source */ 
-       { 0x000007D9, 0x0080 },   /* R2009  - SLIMTX4MIX Input 1 Volume */ 
-       { 0x000007DA, 0x0000 },   /* R2010  - SLIMTX4MIX Input 2 Source */ 
-       { 0x000007DB, 0x0080 },   /* R2011  - SLIMTX4MIX Input 2 Volume */ 
-       { 0x000007DC, 0x0000 },   /* R2012  - SLIMTX4MIX Input 3 Source */ 
-       { 0x000007DD, 0x0080 },   /* R2013  - SLIMTX4MIX Input 3 Volume */ 
-       { 0x000007DE, 0x0000 },   /* R2014  - SLIMTX4MIX Input 4 Source */ 
-       { 0x000007DF, 0x0080 },   /* R2015  - SLIMTX4MIX Input 4 Volume */ 
-       { 0x000007E0, 0x0000 },   /* R2016  - SLIMTX5MIX Input 1 Source */ 
-       { 0x000007E1, 0x0080 },   /* R2017  - SLIMTX5MIX Input 1 Volume */ 
-       { 0x000007E2, 0x0000 },   /* R2018  - SLIMTX5MIX Input 2 Source */ 
-       { 0x000007E3, 0x0080 },   /* R2019  - SLIMTX5MIX Input 2 Volume */ 
-       { 0x000007E4, 0x0000 },   /* R2020  - SLIMTX5MIX Input 3 Source */ 
-       { 0x000007E5, 0x0080 },   /* R2021  - SLIMTX5MIX Input 3 Volume */ 
-       { 0x000007E6, 0x0000 },   /* R2022  - SLIMTX5MIX Input 4 Source */ 
-       { 0x000007E7, 0x0080 },   /* R2023  - SLIMTX5MIX Input 4 Volume */ 
-       { 0x000007E8, 0x0000 },   /* R2024  - SLIMTX6MIX Input 1 Source */ 
-       { 0x000007E9, 0x0080 },   /* R2025  - SLIMTX6MIX Input 1 Volume */ 
-       { 0x000007EA, 0x0000 },   /* R2026  - SLIMTX6MIX Input 2 Source */ 
-       { 0x000007EB, 0x0080 },   /* R2027  - SLIMTX6MIX Input 2 Volume */ 
-       { 0x000007EC, 0x0000 },   /* R2028  - SLIMTX6MIX Input 3 Source */ 
-       { 0x000007ED, 0x0080 },   /* R2029  - SLIMTX6MIX Input 3 Volume */ 
-       { 0x000007EE, 0x0000 },   /* R2030  - SLIMTX6MIX Input 4 Source */ 
-       { 0x000007EF, 0x0080 },   /* R2031  - SLIMTX6MIX Input 4 Volume */ 
-       { 0x000007F0, 0x0000 },   /* R2032  - SLIMTX7MIX Input 1 Source */ 
-       { 0x000007F1, 0x0080 },   /* R2033  - SLIMTX7MIX Input 1 Volume */ 
-       { 0x000007F2, 0x0000 },   /* R2034  - SLIMTX7MIX Input 2 Source */ 
-       { 0x000007F3, 0x0080 },   /* R2035  - SLIMTX7MIX Input 2 Volume */ 
-       { 0x000007F4, 0x0000 },   /* R2036  - SLIMTX7MIX Input 3 Source */ 
-       { 0x000007F5, 0x0080 },   /* R2037  - SLIMTX7MIX Input 3 Volume */ 
-       { 0x000007F6, 0x0000 },   /* R2038  - SLIMTX7MIX Input 4 Source */ 
-       { 0x000007F7, 0x0080 },   /* R2039  - SLIMTX7MIX Input 4 Volume */ 
-       { 0x000007F8, 0x0000 },   /* R2040  - SLIMTX8MIX Input 1 Source */ 
-       { 0x000007F9, 0x0080 },   /* R2041  - SLIMTX8MIX Input 1 Volume */ 
-       { 0x000007FA, 0x0000 },   /* R2042  - SLIMTX8MIX Input 2 Source */ 
-       { 0x000007FB, 0x0080 },   /* R2043  - SLIMTX8MIX Input 2 Volume */ 
-       { 0x000007FC, 0x0000 },   /* R2044  - SLIMTX8MIX Input 3 Source */ 
-       { 0x000007FD, 0x0080 },   /* R2045  - SLIMTX8MIX Input 3 Volume */ 
-       { 0x000007FE, 0x0000 },   /* R2046  - SLIMTX8MIX Input 4 Source */ 
-       { 0x000007FF, 0x0080 },   /* R2047  - SLIMTX8MIX Input 4 Volume */ 
-       { 0x00000880, 0x0000 },   /* R2176  - EQ1MIX Input 1 Source */ 
-       { 0x00000881, 0x0080 },   /* R2177  - EQ1MIX Input 1 Volume */ 
-       { 0x00000882, 0x0000 },   /* R2178  - EQ1MIX Input 2 Source */ 
-       { 0x00000883, 0x0080 },   /* R2179  - EQ1MIX Input 2 Volume */ 
-       { 0x00000884, 0x0000 },   /* R2180  - EQ1MIX Input 3 Source */ 
-       { 0x00000885, 0x0080 },   /* R2181  - EQ1MIX Input 3 Volume */ 
-       { 0x00000886, 0x0000 },   /* R2182  - EQ1MIX Input 4 Source */ 
-       { 0x00000887, 0x0080 },   /* R2183  - EQ1MIX Input 4 Volume */ 
-       { 0x00000888, 0x0000 },   /* R2184  - EQ2MIX Input 1 Source */ 
-       { 0x00000889, 0x0080 },   /* R2185  - EQ2MIX Input 1 Volume */ 
-       { 0x0000088A, 0x0000 },   /* R2186  - EQ2MIX Input 2 Source */ 
-       { 0x0000088B, 0x0080 },   /* R2187  - EQ2MIX Input 2 Volume */ 
-       { 0x0000088C, 0x0000 },   /* R2188  - EQ2MIX Input 3 Source */ 
-       { 0x0000088D, 0x0080 },   /* R2189  - EQ2MIX Input 3 Volume */ 
-       { 0x0000088E, 0x0000 },   /* R2190  - EQ2MIX Input 4 Source */ 
-       { 0x0000088F, 0x0080 },   /* R2191  - EQ2MIX Input 4 Volume */ 
-       { 0x00000890, 0x0000 },   /* R2192  - EQ3MIX Input 1 Source */ 
-       { 0x00000891, 0x0080 },   /* R2193  - EQ3MIX Input 1 Volume */ 
-       { 0x00000892, 0x0000 },   /* R2194  - EQ3MIX Input 2 Source */ 
-       { 0x00000893, 0x0080 },   /* R2195  - EQ3MIX Input 2 Volume */ 
-       { 0x00000894, 0x0000 },   /* R2196  - EQ3MIX Input 3 Source */ 
-       { 0x00000895, 0x0080 },   /* R2197  - EQ3MIX Input 3 Volume */ 
-       { 0x00000896, 0x0000 },   /* R2198  - EQ3MIX Input 4 Source */ 
-       { 0x00000897, 0x0080 },   /* R2199  - EQ3MIX Input 4 Volume */ 
-       { 0x00000898, 0x0000 },   /* R2200  - EQ4MIX Input 1 Source */ 
-       { 0x00000899, 0x0080 },   /* R2201  - EQ4MIX Input 1 Volume */ 
-       { 0x0000089A, 0x0000 },   /* R2202  - EQ4MIX Input 2 Source */ 
-       { 0x0000089B, 0x0080 },   /* R2203  - EQ4MIX Input 2 Volume */ 
-       { 0x0000089C, 0x0000 },   /* R2204  - EQ4MIX Input 3 Source */ 
-       { 0x0000089D, 0x0080 },   /* R2205  - EQ4MIX Input 3 Volume */ 
-       { 0x0000089E, 0x0000 },   /* R2206  - EQ4MIX Input 4 Source */ 
-       { 0x0000089F, 0x0080 },   /* R2207  - EQ4MIX Input 4 Volume */ 
-       { 0x000008C0, 0x0000 },   /* R2240  - DRC1LMIX Input 1 Source */ 
-       { 0x000008C1, 0x0080 },   /* R2241  - DRC1LMIX Input 1 Volume */ 
-       { 0x000008C2, 0x0000 },   /* R2242  - DRC1LMIX Input 2 Source */ 
-       { 0x000008C3, 0x0080 },   /* R2243  - DRC1LMIX Input 2 Volume */ 
-       { 0x000008C4, 0x0000 },   /* R2244  - DRC1LMIX Input 3 Source */ 
-       { 0x000008C5, 0x0080 },   /* R2245  - DRC1LMIX Input 3 Volume */ 
-       { 0x000008C6, 0x0000 },   /* R2246  - DRC1LMIX Input 4 Source */ 
-       { 0x000008C7, 0x0080 },   /* R2247  - DRC1LMIX Input 4 Volume */ 
-       { 0x000008C8, 0x0000 },   /* R2248  - DRC1RMIX Input 1 Source */ 
-       { 0x000008C9, 0x0080 },   /* R2249  - DRC1RMIX Input 1 Volume */ 
-       { 0x000008CA, 0x0000 },   /* R2250  - DRC1RMIX Input 2 Source */ 
-       { 0x000008CB, 0x0080 },   /* R2251  - DRC1RMIX Input 2 Volume */ 
-       { 0x000008CC, 0x0000 },   /* R2252  - DRC1RMIX Input 3 Source */ 
-       { 0x000008CD, 0x0080 },   /* R2253  - DRC1RMIX Input 3 Volume */ 
-       { 0x000008CE, 0x0000 },   /* R2254  - DRC1RMIX Input 4 Source */ 
-       { 0x000008CF, 0x0080 },   /* R2255  - DRC1RMIX Input 4 Volume */ 
-       { 0x00000900, 0x0000 },   /* R2304  - HPLP1MIX Input 1 Source */ 
-       { 0x00000901, 0x0080 },   /* R2305  - HPLP1MIX Input 1 Volume */ 
-       { 0x00000902, 0x0000 },   /* R2306  - HPLP1MIX Input 2 Source */ 
-       { 0x00000903, 0x0080 },   /* R2307  - HPLP1MIX Input 2 Volume */ 
-       { 0x00000904, 0x0000 },   /* R2308  - HPLP1MIX Input 3 Source */ 
-       { 0x00000905, 0x0080 },   /* R2309  - HPLP1MIX Input 3 Volume */ 
-       { 0x00000906, 0x0000 },   /* R2310  - HPLP1MIX Input 4 Source */ 
-       { 0x00000907, 0x0080 },   /* R2311  - HPLP1MIX Input 4 Volume */ 
-       { 0x00000908, 0x0000 },   /* R2312  - HPLP2MIX Input 1 Source */ 
-       { 0x00000909, 0x0080 },   /* R2313  - HPLP2MIX Input 1 Volume */ 
-       { 0x0000090A, 0x0000 },   /* R2314  - HPLP2MIX Input 2 Source */ 
-       { 0x0000090B, 0x0080 },   /* R2315  - HPLP2MIX Input 2 Volume */ 
-       { 0x0000090C, 0x0000 },   /* R2316  - HPLP2MIX Input 3 Source */ 
-       { 0x0000090D, 0x0080 },   /* R2317  - HPLP2MIX Input 3 Volume */ 
-       { 0x0000090E, 0x0000 },   /* R2318  - HPLP2MIX Input 4 Source */ 
-       { 0x0000090F, 0x0080 },   /* R2319  - HPLP2MIX Input 4 Volume */ 
-       { 0x00000910, 0x0000 },   /* R2320  - HPLP3MIX Input 1 Source */ 
-       { 0x00000911, 0x0080 },   /* R2321  - HPLP3MIX Input 1 Volume */ 
-       { 0x00000912, 0x0000 },   /* R2322  - HPLP3MIX Input 2 Source */ 
-       { 0x00000913, 0x0080 },   /* R2323  - HPLP3MIX Input 2 Volume */ 
-       { 0x00000914, 0x0000 },   /* R2324  - HPLP3MIX Input 3 Source */ 
-       { 0x00000915, 0x0080 },   /* R2325  - HPLP3MIX Input 3 Volume */ 
-       { 0x00000916, 0x0000 },   /* R2326  - HPLP3MIX Input 4 Source */ 
-       { 0x00000917, 0x0080 },   /* R2327  - HPLP3MIX Input 4 Volume */ 
-       { 0x00000918, 0x0000 },   /* R2328  - HPLP4MIX Input 1 Source */ 
-       { 0x00000919, 0x0080 },   /* R2329  - HPLP4MIX Input 1 Volume */ 
-       { 0x0000091A, 0x0000 },   /* R2330  - HPLP4MIX Input 2 Source */ 
-       { 0x0000091B, 0x0080 },   /* R2331  - HPLP4MIX Input 2 Volume */ 
-       { 0x0000091C, 0x0000 },   /* R2332  - HPLP4MIX Input 3 Source */ 
-       { 0x0000091D, 0x0080 },   /* R2333  - HPLP4MIX Input 3 Volume */ 
-       { 0x0000091E, 0x0000 },   /* R2334  - HPLP4MIX Input 4 Source */ 
-       { 0x0000091F, 0x0080 },   /* R2335  - HPLP4MIX Input 4 Volume */ 
-       { 0x00000940, 0x0000 },   /* R2368  - DSP1LMIX Input 1 Source */ 
-       { 0x00000941, 0x0080 },   /* R2369  - DSP1LMIX Input 1 Volume */ 
-       { 0x00000942, 0x0000 },   /* R2370  - DSP1LMIX Input 2 Source */ 
-       { 0x00000943, 0x0080 },   /* R2371  - DSP1LMIX Input 2 Volume */ 
-       { 0x00000944, 0x0000 },   /* R2372  - DSP1LMIX Input 3 Source */ 
-       { 0x00000945, 0x0080 },   /* R2373  - DSP1LMIX Input 3 Volume */ 
-       { 0x00000946, 0x0000 },   /* R2374  - DSP1LMIX Input 4 Source */ 
-       { 0x00000947, 0x0080 },   /* R2375  - DSP1LMIX Input 4 Volume */ 
-       { 0x00000948, 0x0000 },   /* R2376  - DSP1RMIX Input 1 Source */ 
-       { 0x00000949, 0x0080 },   /* R2377  - DSP1RMIX Input 1 Volume */ 
-       { 0x0000094A, 0x0000 },   /* R2378  - DSP1RMIX Input 2 Source */ 
-       { 0x0000094B, 0x0080 },   /* R2379  - DSP1RMIX Input 2 Volume */ 
-       { 0x0000094C, 0x0000 },   /* R2380  - DSP1RMIX Input 3 Source */ 
-       { 0x0000094D, 0x0080 },   /* R2381  - DSP1RMIX Input 3 Volume */ 
-       { 0x0000094E, 0x0000 },   /* R2382  - DSP1RMIX Input 4 Source */ 
-       { 0x0000094F, 0x0080 },   /* R2383  - DSP1RMIX Input 4 Volume */ 
-       { 0x00000950, 0x0000 },   /* R2384  - DSP1AUX1MIX Input 1 Source */ 
-       { 0x00000958, 0x0000 },   /* R2392  - DSP1AUX2MIX Input 1 Source */ 
-       { 0x00000960, 0x0000 },   /* R2400  - DSP1AUX3MIX Input 1 Source */ 
-       { 0x00000968, 0x0000 },   /* R2408  - DSP1AUX4MIX Input 1 Source */ 
-       { 0x00000970, 0x0000 },   /* R2416  - DSP1AUX5MIX Input 1 Source */ 
-       { 0x00000978, 0x0000 },   /* R2424  - DSP1AUX6MIX Input 1 Source */ 
-       { 0x00000A80, 0x0000 },   /* R2688  - ASRC1LMIX Input 1 Source */ 
-       { 0x00000A88, 0x0000 },   /* R2696  - ASRC1RMIX Input 1 Source */ 
-       { 0x00000A90, 0x0000 },   /* R2704  - ASRC2LMIX Input 1 Source */ 
-       { 0x00000A98, 0x0000 },   /* R2712  - ASRC2RMIX Input 1 Source */ 
-       { 0x00000B00, 0x0000 },   /* R2816  - ISRC1DEC1MIX Input 1 Source */ 
-       { 0x00000B08, 0x0000 },   /* R2824  - ISRC1DEC2MIX Input 1 Source */ 
-       { 0x00000B20, 0x0000 },   /* R2848  - ISRC1INT1MIX Input 1 Source */ 
-       { 0x00000B28, 0x0000 },   /* R2856  - ISRC1INT2MIX Input 1 Source */ 
-       { 0x00000B40, 0x0000 },   /* R2880  - ISRC2DEC1MIX Input 1 Source */ 
-       { 0x00000B48, 0x0000 },   /* R2888  - ISRC2DEC2MIX Input 1 Source */ 
-       { 0x00000B60, 0x0000 },   /* R2912  - ISRC2INT1MIX Input 1 Source */ 
-       { 0x00000B68, 0x0000 },   /* R2920  - ISRC2INT2MIX Input 1 Source */ 
-       { 0x00000C00, 0xA101 },   /* R3072  - GPIO1 CTRL */ 
-       { 0x00000C01, 0xA101 },   /* R3073  - GPIO2 CTRL */ 
-       { 0x00000C02, 0xA101 },   /* R3074  - GPIO3 CTRL */ 
-       { 0x00000C03, 0xA101 },   /* R3075  - GPIO4 CTRL */ 
-       { 0x00000C04, 0xA101 },   /* R3076  - GPIO5 CTRL */ 
-       { 0x00000C0F, 0x0400 },   /* R3087  - IRQ CTRL 1 */ 
-       { 0x00000C10, 0x1000 },   /* R3088  - GPIO Debounce Config */ 
-       { 0x00000C20, 0x8002 },   /* R3104  - Misc Pad Ctrl 1 */ 
+       { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */
+       { 0x00000491, 0x0000 },   /* R1169  - PDM SPK1 CTRL 2 */
+       { 0x00000500, 0x000C },   /* R1280  - AIF1 BCLK Ctrl */
+       { 0x00000501, 0x0008 },   /* R1281  - AIF1 Tx Pin Ctrl */
+       { 0x00000502, 0x0000 },   /* R1282  - AIF1 Rx Pin Ctrl */
+       { 0x00000503, 0x0000 },   /* R1283  - AIF1 Rate Ctrl */
+       { 0x00000504, 0x0000 },   /* R1284  - AIF1 Format */
+       { 0x00000505, 0x0040 },   /* R1285  - AIF1 Tx BCLK Rate */
+       { 0x00000506, 0x0040 },   /* R1286  - AIF1 Rx BCLK Rate */
+       { 0x00000507, 0x1818 },   /* R1287  - AIF1 Frame Ctrl 1 */
+       { 0x00000508, 0x1818 },   /* R1288  - AIF1 Frame Ctrl 2 */
+       { 0x00000509, 0x0000 },   /* R1289  - AIF1 Frame Ctrl 3 */
+       { 0x0000050A, 0x0001 },   /* R1290  - AIF1 Frame Ctrl 4 */
+       { 0x0000050B, 0x0002 },   /* R1291  - AIF1 Frame Ctrl 5 */
+       { 0x0000050C, 0x0003 },   /* R1292  - AIF1 Frame Ctrl 6 */
+       { 0x0000050D, 0x0004 },   /* R1293  - AIF1 Frame Ctrl 7 */
+       { 0x0000050E, 0x0005 },   /* R1294  - AIF1 Frame Ctrl 8 */
+       { 0x0000050F, 0x0006 },   /* R1295  - AIF1 Frame Ctrl 9 */
+       { 0x00000510, 0x0007 },   /* R1296  - AIF1 Frame Ctrl 10 */
+       { 0x00000511, 0x0000 },   /* R1297  - AIF1 Frame Ctrl 11 */
+       { 0x00000512, 0x0001 },   /* R1298  - AIF1 Frame Ctrl 12 */
+       { 0x00000513, 0x0002 },   /* R1299  - AIF1 Frame Ctrl 13 */
+       { 0x00000514, 0x0003 },   /* R1300  - AIF1 Frame Ctrl 14 */
+       { 0x00000515, 0x0004 },   /* R1301  - AIF1 Frame Ctrl 15 */
+       { 0x00000516, 0x0005 },   /* R1302  - AIF1 Frame Ctrl 16 */
+       { 0x00000517, 0x0006 },   /* R1303  - AIF1 Frame Ctrl 17 */
+       { 0x00000518, 0x0007 },   /* R1304  - AIF1 Frame Ctrl 18 */
+       { 0x00000519, 0x0000 },   /* R1305  - AIF1 Tx Enables */
+       { 0x0000051A, 0x0000 },   /* R1306  - AIF1 Rx Enables */
+       { 0x00000540, 0x000C },   /* R1344  - AIF2 BCLK Ctrl */
+       { 0x00000541, 0x0008 },   /* R1345  - AIF2 Tx Pin Ctrl */
+       { 0x00000542, 0x0000 },   /* R1346  - AIF2 Rx Pin Ctrl */
+       { 0x00000543, 0x0000 },   /* R1347  - AIF2 Rate Ctrl */
+       { 0x00000544, 0x0000 },   /* R1348  - AIF2 Format */
+       { 0x00000545, 0x0040 },   /* R1349  - AIF2 Tx BCLK Rate */
+       { 0x00000546, 0x0040 },   /* R1350  - AIF2 Rx BCLK Rate */
+       { 0x00000547, 0x1818 },   /* R1351  - AIF2 Frame Ctrl 1 */
+       { 0x00000548, 0x1818 },   /* R1352  - AIF2 Frame Ctrl 2 */
+       { 0x00000549, 0x0000 },   /* R1353  - AIF2 Frame Ctrl 3 */
+       { 0x0000054A, 0x0001 },   /* R1354  - AIF2 Frame Ctrl 4 */
+       { 0x00000551, 0x0000 },   /* R1361  - AIF2 Frame Ctrl 11 */
+       { 0x00000552, 0x0001 },   /* R1362  - AIF2 Frame Ctrl 12 */
+       { 0x00000559, 0x0000 },   /* R1369  - AIF2 Tx Enables */
+       { 0x0000055A, 0x0000 },   /* R1370  - AIF2 Rx Enables */
+       { 0x00000580, 0x000C },   /* R1408  - AIF3 BCLK Ctrl */
+       { 0x00000581, 0x0008 },   /* R1409  - AIF3 Tx Pin Ctrl */
+       { 0x00000582, 0x0000 },   /* R1410  - AIF3 Rx Pin Ctrl */
+       { 0x00000583, 0x0000 },   /* R1411  - AIF3 Rate Ctrl */
+       { 0x00000584, 0x0000 },   /* R1412  - AIF3 Format */
+       { 0x00000585, 0x0040 },   /* R1413  - AIF3 Tx BCLK Rate */
+       { 0x00000586, 0x0040 },   /* R1414  - AIF3 Rx BCLK Rate */
+       { 0x00000587, 0x1818 },   /* R1415  - AIF3 Frame Ctrl 1 */
+       { 0x00000588, 0x1818 },   /* R1416  - AIF3 Frame Ctrl 2 */
+       { 0x00000589, 0x0000 },   /* R1417  - AIF3 Frame Ctrl 3 */
+       { 0x0000058A, 0x0001 },   /* R1418  - AIF3 Frame Ctrl 4 */
+       { 0x00000591, 0x0000 },   /* R1425  - AIF3 Frame Ctrl 11 */
+       { 0x00000592, 0x0001 },   /* R1426  - AIF3 Frame Ctrl 12 */
+       { 0x00000599, 0x0000 },   /* R1433  - AIF3 Tx Enables */
+       { 0x0000059A, 0x0000 },   /* R1434  - AIF3 Rx Enables */
+       { 0x000005E3, 0x0004 },   /* R1507  - SLIMbus Framer Ref Gear */
+       { 0x000005E5, 0x0000 },   /* R1509  - SLIMbus Rates 1 */
+       { 0x000005E6, 0x0000 },   /* R1510  - SLIMbus Rates 2 */
+       { 0x000005E7, 0x0000 },   /* R1511  - SLIMbus Rates 3 */
+       { 0x000005E8, 0x0000 },   /* R1512  - SLIMbus Rates 4 */
+       { 0x000005E9, 0x0000 },   /* R1513  - SLIMbus Rates 5 */
+       { 0x000005EA, 0x0000 },   /* R1514  - SLIMbus Rates 6 */
+       { 0x000005EB, 0x0000 },   /* R1515  - SLIMbus Rates 7 */
+       { 0x000005EC, 0x0000 },   /* R1516  - SLIMbus Rates 8 */
+       { 0x000005F5, 0x0000 },   /* R1525  - SLIMbus RX Channel Enable */
+       { 0x000005F6, 0x0000 },   /* R1526  - SLIMbus TX Channel Enable */
+       { 0x00000640, 0x0000 },   /* R1600  - PWM1MIX Input 1 Source */
+       { 0x00000641, 0x0080 },   /* R1601  - PWM1MIX Input 1 Volume */
+       { 0x00000642, 0x0000 },   /* R1602  - PWM1MIX Input 2 Source */
+       { 0x00000643, 0x0080 },   /* R1603  - PWM1MIX Input 2 Volume */
+       { 0x00000644, 0x0000 },   /* R1604  - PWM1MIX Input 3 Source */
+       { 0x00000645, 0x0080 },   /* R1605  - PWM1MIX Input 3 Volume */
+       { 0x00000646, 0x0000 },   /* R1606  - PWM1MIX Input 4 Source */
+       { 0x00000647, 0x0080 },   /* R1607  - PWM1MIX Input 4 Volume */
+       { 0x00000648, 0x0000 },   /* R1608  - PWM2MIX Input 1 Source */
+       { 0x00000649, 0x0080 },   /* R1609  - PWM2MIX Input 1 Volume */
+       { 0x0000064A, 0x0000 },   /* R1610  - PWM2MIX Input 2 Source */
+       { 0x0000064B, 0x0080 },   /* R1611  - PWM2MIX Input 2 Volume */
+       { 0x0000064C, 0x0000 },   /* R1612  - PWM2MIX Input 3 Source */
+       { 0x0000064D, 0x0080 },   /* R1613  - PWM2MIX Input 3 Volume */
+       { 0x0000064E, 0x0000 },   /* R1614  - PWM2MIX Input 4 Source */
+       { 0x0000064F, 0x0080 },   /* R1615  - PWM2MIX Input 4 Volume */
+       { 0x00000660, 0x0000 },   /* R1632  - MICMIX Input 1 Source */
+       { 0x00000661, 0x0080 },   /* R1633  - MICMIX Input 1 Volume */
+       { 0x00000662, 0x0000 },   /* R1634  - MICMIX Input 2 Source */
+       { 0x00000663, 0x0080 },   /* R1635  - MICMIX Input 2 Volume */
+       { 0x00000664, 0x0000 },   /* R1636  - MICMIX Input 3 Source */
+       { 0x00000665, 0x0080 },   /* R1637  - MICMIX Input 3 Volume */
+       { 0x00000666, 0x0000 },   /* R1638  - MICMIX Input 4 Source */
+       { 0x00000667, 0x0080 },   /* R1639  - MICMIX Input 4 Volume */
+       { 0x00000668, 0x0000 },   /* R1640  - NOISEMIX Input 1 Source */
+       { 0x00000669, 0x0080 },   /* R1641  - NOISEMIX Input 1 Volume */
+       { 0x0000066A, 0x0000 },   /* R1642  - NOISEMIX Input 2 Source */
+       { 0x0000066B, 0x0080 },   /* R1643  - NOISEMIX Input 2 Volume */
+       { 0x0000066C, 0x0000 },   /* R1644  - NOISEMIX Input 3 Source */
+       { 0x0000066D, 0x0080 },   /* R1645  - NOISEMIX Input 3 Volume */
+       { 0x0000066E, 0x0000 },   /* R1646  - NOISEMIX Input 4 Source */
+       { 0x0000066F, 0x0080 },   /* R1647  - NOISEMIX Input 4 Volume */
+       { 0x00000680, 0x0000 },   /* R1664  - OUT1LMIX Input 1 Source */
+       { 0x00000681, 0x0080 },   /* R1665  - OUT1LMIX Input 1 Volume */
+       { 0x00000682, 0x0000 },   /* R1666  - OUT1LMIX Input 2 Source */
+       { 0x00000683, 0x0080 },   /* R1667  - OUT1LMIX Input 2 Volume */
+       { 0x00000684, 0x0000 },   /* R1668  - OUT1LMIX Input 3 Source */
+       { 0x00000685, 0x0080 },   /* R1669  - OUT1LMIX Input 3 Volume */
+       { 0x00000686, 0x0000 },   /* R1670  - OUT1LMIX Input 4 Source */
+       { 0x00000687, 0x0080 },   /* R1671  - OUT1LMIX Input 4 Volume */
+       { 0x00000688, 0x0000 },   /* R1672  - OUT1RMIX Input 1 Source */
+       { 0x00000689, 0x0080 },   /* R1673  - OUT1RMIX Input 1 Volume */
+       { 0x0000068A, 0x0000 },   /* R1674  - OUT1RMIX Input 2 Source */
+       { 0x0000068B, 0x0080 },   /* R1675  - OUT1RMIX Input 2 Volume */
+       { 0x0000068C, 0x0000 },   /* R1676  - OUT1RMIX Input 3 Source */
+       { 0x0000068D, 0x0080 },   /* R1677  - OUT1RMIX Input 3 Volume */
+       { 0x0000068E, 0x0000 },   /* R1678  - OUT1RMIX Input 4 Source */
+       { 0x0000068F, 0x0080 },   /* R1679  - OUT1RMIX Input 4 Volume */
+       { 0x00000690, 0x0000 },   /* R1680  - OUT2LMIX Input 1 Source */
+       { 0x00000691, 0x0080 },   /* R1681  - OUT2LMIX Input 1 Volume */
+       { 0x00000692, 0x0000 },   /* R1682  - OUT2LMIX Input 2 Source */
+       { 0x00000693, 0x0080 },   /* R1683  - OUT2LMIX Input 2 Volume */
+       { 0x00000694, 0x0000 },   /* R1684  - OUT2LMIX Input 3 Source */
+       { 0x00000695, 0x0080 },   /* R1685  - OUT2LMIX Input 3 Volume */
+       { 0x00000696, 0x0000 },   /* R1686  - OUT2LMIX Input 4 Source */
+       { 0x00000697, 0x0080 },   /* R1687  - OUT2LMIX Input 4 Volume */
+       { 0x00000698, 0x0000 },   /* R1688  - OUT2RMIX Input 1 Source */
+       { 0x00000699, 0x0080 },   /* R1689  - OUT2RMIX Input 1 Volume */
+       { 0x0000069A, 0x0000 },   /* R1690  - OUT2RMIX Input 2 Source */
+       { 0x0000069B, 0x0080 },   /* R1691  - OUT2RMIX Input 2 Volume */
+       { 0x0000069C, 0x0000 },   /* R1692  - OUT2RMIX Input 3 Source */
+       { 0x0000069D, 0x0080 },   /* R1693  - OUT2RMIX Input 3 Volume */
+       { 0x0000069E, 0x0000 },   /* R1694  - OUT2RMIX Input 4 Source */
+       { 0x0000069F, 0x0080 },   /* R1695  - OUT2RMIX Input 4 Volume */
+       { 0x000006A0, 0x0000 },   /* R1696  - OUT3LMIX Input 1 Source */
+       { 0x000006A1, 0x0080 },   /* R1697  - OUT3LMIX Input 1 Volume */
+       { 0x000006A2, 0x0000 },   /* R1698  - OUT3LMIX Input 2 Source */
+       { 0x000006A3, 0x0080 },   /* R1699  - OUT3LMIX Input 2 Volume */
+       { 0x000006A4, 0x0000 },   /* R1700  - OUT3LMIX Input 3 Source */
+       { 0x000006A5, 0x0080 },   /* R1701  - OUT3LMIX Input 3 Volume */
+       { 0x000006A6, 0x0000 },   /* R1702  - OUT3LMIX Input 4 Source */
+       { 0x000006A7, 0x0080 },   /* R1703  - OUT3LMIX Input 4 Volume */
+       { 0x000006B0, 0x0000 },   /* R1712  - OUT4LMIX Input 1 Source */
+       { 0x000006B1, 0x0080 },   /* R1713  - OUT4LMIX Input 1 Volume */
+       { 0x000006B2, 0x0000 },   /* R1714  - OUT4LMIX Input 2 Source */
+       { 0x000006B3, 0x0080 },   /* R1715  - OUT4LMIX Input 2 Volume */
+       { 0x000006B4, 0x0000 },   /* R1716  - OUT4LMIX Input 3 Source */
+       { 0x000006B5, 0x0080 },   /* R1717  - OUT4LMIX Input 3 Volume */
+       { 0x000006B6, 0x0000 },   /* R1718  - OUT4LMIX Input 4 Source */
+       { 0x000006B7, 0x0080 },   /* R1719  - OUT4LMIX Input 4 Volume */
+       { 0x000006B8, 0x0000 },   /* R1720  - OUT4RMIX Input 1 Source */
+       { 0x000006B9, 0x0080 },   /* R1721  - OUT4RMIX Input 1 Volume */
+       { 0x000006BA, 0x0000 },   /* R1722  - OUT4RMIX Input 2 Source */
+       { 0x000006BB, 0x0080 },   /* R1723  - OUT4RMIX Input 2 Volume */
+       { 0x000006BC, 0x0000 },   /* R1724  - OUT4RMIX Input 3 Source */
+       { 0x000006BD, 0x0080 },   /* R1725  - OUT4RMIX Input 3 Volume */
+       { 0x000006BE, 0x0000 },   /* R1726  - OUT4RMIX Input 4 Source */
+       { 0x000006BF, 0x0080 },   /* R1727  - OUT4RMIX Input 4 Volume */
+       { 0x000006C0, 0x0000 },   /* R1728  - OUT5LMIX Input 1 Source */
+       { 0x000006C1, 0x0080 },   /* R1729  - OUT5LMIX Input 1 Volume */
+       { 0x000006C2, 0x0000 },   /* R1730  - OUT5LMIX Input 2 Source */
+       { 0x000006C3, 0x0080 },   /* R1731  - OUT5LMIX Input 2 Volume */
+       { 0x000006C4, 0x0000 },   /* R1732  - OUT5LMIX Input 3 Source */
+       { 0x000006C5, 0x0080 },   /* R1733  - OUT5LMIX Input 3 Volume */
+       { 0x000006C6, 0x0000 },   /* R1734  - OUT5LMIX Input 4 Source */
+       { 0x000006C7, 0x0080 },   /* R1735  - OUT5LMIX Input 4 Volume */
+       { 0x000006C8, 0x0000 },   /* R1736  - OUT5RMIX Input 1 Source */
+       { 0x000006C9, 0x0080 },   /* R1737  - OUT5RMIX Input 1 Volume */
+       { 0x000006CA, 0x0000 },   /* R1738  - OUT5RMIX Input 2 Source */
+       { 0x000006CB, 0x0080 },   /* R1739  - OUT5RMIX Input 2 Volume */
+       { 0x000006CC, 0x0000 },   /* R1740  - OUT5RMIX Input 3 Source */
+       { 0x000006CD, 0x0080 },   /* R1741  - OUT5RMIX Input 3 Volume */
+       { 0x000006CE, 0x0000 },   /* R1742  - OUT5RMIX Input 4 Source */
+       { 0x000006CF, 0x0080 },   /* R1743  - OUT5RMIX Input 4 Volume */
+       { 0x00000700, 0x0000 },   /* R1792  - AIF1TX1MIX Input 1 Source */
+       { 0x00000701, 0x0080 },   /* R1793  - AIF1TX1MIX Input 1 Volume */
+       { 0x00000702, 0x0000 },   /* R1794  - AIF1TX1MIX Input 2 Source */
+       { 0x00000703, 0x0080 },   /* R1795  - AIF1TX1MIX Input 2 Volume */
+       { 0x00000704, 0x0000 },   /* R1796  - AIF1TX1MIX Input 3 Source */
+       { 0x00000705, 0x0080 },   /* R1797  - AIF1TX1MIX Input 3 Volume */
+       { 0x00000706, 0x0000 },   /* R1798  - AIF1TX1MIX Input 4 Source */
+       { 0x00000707, 0x0080 },   /* R1799  - AIF1TX1MIX Input 4 Volume */
+       { 0x00000708, 0x0000 },   /* R1800  - AIF1TX2MIX Input 1 Source */
+       { 0x00000709, 0x0080 },   /* R1801  - AIF1TX2MIX Input 1 Volume */
+       { 0x0000070A, 0x0000 },   /* R1802  - AIF1TX2MIX Input 2 Source */
+       { 0x0000070B, 0x0080 },   /* R1803  - AIF1TX2MIX Input 2 Volume */
+       { 0x0000070C, 0x0000 },   /* R1804  - AIF1TX2MIX Input 3 Source */
+       { 0x0000070D, 0x0080 },   /* R1805  - AIF1TX2MIX Input 3 Volume */
+       { 0x0000070E, 0x0000 },   /* R1806  - AIF1TX2MIX Input 4 Source */
+       { 0x0000070F, 0x0080 },   /* R1807  - AIF1TX2MIX Input 4 Volume */
+       { 0x00000710, 0x0000 },   /* R1808  - AIF1TX3MIX Input 1 Source */
+       { 0x00000711, 0x0080 },   /* R1809  - AIF1TX3MIX Input 1 Volume */
+       { 0x00000712, 0x0000 },   /* R1810  - AIF1TX3MIX Input 2 Source */
+       { 0x00000713, 0x0080 },   /* R1811  - AIF1TX3MIX Input 2 Volume */
+       { 0x00000714, 0x0000 },   /* R1812  - AIF1TX3MIX Input 3 Source */
+       { 0x00000715, 0x0080 },   /* R1813  - AIF1TX3MIX Input 3 Volume */
+       { 0x00000716, 0x0000 },   /* R1814  - AIF1TX3MIX Input 4 Source */
+       { 0x00000717, 0x0080 },   /* R1815  - AIF1TX3MIX Input 4 Volume */
+       { 0x00000718, 0x0000 },   /* R1816  - AIF1TX4MIX Input 1 Source */
+       { 0x00000719, 0x0080 },   /* R1817  - AIF1TX4MIX Input 1 Volume */
+       { 0x0000071A, 0x0000 },   /* R1818  - AIF1TX4MIX Input 2 Source */
+       { 0x0000071B, 0x0080 },   /* R1819  - AIF1TX4MIX Input 2 Volume */
+       { 0x0000071C, 0x0000 },   /* R1820  - AIF1TX4MIX Input 3 Source */
+       { 0x0000071D, 0x0080 },   /* R1821  - AIF1TX4MIX Input 3 Volume */
+       { 0x0000071E, 0x0000 },   /* R1822  - AIF1TX4MIX Input 4 Source */
+       { 0x0000071F, 0x0080 },   /* R1823  - AIF1TX4MIX Input 4 Volume */
+       { 0x00000720, 0x0000 },   /* R1824  - AIF1TX5MIX Input 1 Source */
+       { 0x00000721, 0x0080 },   /* R1825  - AIF1TX5MIX Input 1 Volume */
+       { 0x00000722, 0x0000 },   /* R1826  - AIF1TX5MIX Input 2 Source */
+       { 0x00000723, 0x0080 },   /* R1827  - AIF1TX5MIX Input 2 Volume */
+       { 0x00000724, 0x0000 },   /* R1828  - AIF1TX5MIX Input 3 Source */
+       { 0x00000725, 0x0080 },   /* R1829  - AIF1TX5MIX Input 3 Volume */
+       { 0x00000726, 0x0000 },   /* R1830  - AIF1TX5MIX Input 4 Source */
+       { 0x00000727, 0x0080 },   /* R1831  - AIF1TX5MIX Input 4 Volume */
+       { 0x00000728, 0x0000 },   /* R1832  - AIF1TX6MIX Input 1 Source */
+       { 0x00000729, 0x0080 },   /* R1833  - AIF1TX6MIX Input 1 Volume */
+       { 0x0000072A, 0x0000 },   /* R1834  - AIF1TX6MIX Input 2 Source */
+       { 0x0000072B, 0x0080 },   /* R1835  - AIF1TX6MIX Input 2 Volume */
+       { 0x0000072C, 0x0000 },   /* R1836  - AIF1TX6MIX Input 3 Source */
+       { 0x0000072D, 0x0080 },   /* R1837  - AIF1TX6MIX Input 3 Volume */
+       { 0x0000072E, 0x0000 },   /* R1838  - AIF1TX6MIX Input 4 Source */
+       { 0x0000072F, 0x0080 },   /* R1839  - AIF1TX6MIX Input 4 Volume */
+       { 0x00000730, 0x0000 },   /* R1840  - AIF1TX7MIX Input 1 Source */
+       { 0x00000731, 0x0080 },   /* R1841  - AIF1TX7MIX Input 1 Volume */
+       { 0x00000732, 0x0000 },   /* R1842  - AIF1TX7MIX Input 2 Source */
+       { 0x00000733, 0x0080 },   /* R1843  - AIF1TX7MIX Input 2 Volume */
+       { 0x00000734, 0x0000 },   /* R1844  - AIF1TX7MIX Input 3 Source */
+       { 0x00000735, 0x0080 },   /* R1845  - AIF1TX7MIX Input 3 Volume */
+       { 0x00000736, 0x0000 },   /* R1846  - AIF1TX7MIX Input 4 Source */
+       { 0x00000737, 0x0080 },   /* R1847  - AIF1TX7MIX Input 4 Volume */
+       { 0x00000738, 0x0000 },   /* R1848  - AIF1TX8MIX Input 1 Source */
+       { 0x00000739, 0x0080 },   /* R1849  - AIF1TX8MIX Input 1 Volume */
+       { 0x0000073A, 0x0000 },   /* R1850  - AIF1TX8MIX Input 2 Source */
+       { 0x0000073B, 0x0080 },   /* R1851  - AIF1TX8MIX Input 2 Volume */
+       { 0x0000073C, 0x0000 },   /* R1852  - AIF1TX8MIX Input 3 Source */
+       { 0x0000073D, 0x0080 },   /* R1853  - AIF1TX8MIX Input 3 Volume */
+       { 0x0000073E, 0x0000 },   /* R1854  - AIF1TX8MIX Input 4 Source */
+       { 0x0000073F, 0x0080 },   /* R1855  - AIF1TX8MIX Input 4 Volume */
+       { 0x00000740, 0x0000 },   /* R1856  - AIF2TX1MIX Input 1 Source */
+       { 0x00000741, 0x0080 },   /* R1857  - AIF2TX1MIX Input 1 Volume */
+       { 0x00000742, 0x0000 },   /* R1858  - AIF2TX1MIX Input 2 Source */
+       { 0x00000743, 0x0080 },   /* R1859  - AIF2TX1MIX Input 2 Volume */
+       { 0x00000744, 0x0000 },   /* R1860  - AIF2TX1MIX Input 3 Source */
+       { 0x00000745, 0x0080 },   /* R1861  - AIF2TX1MIX Input 3 Volume */
+       { 0x00000746, 0x0000 },   /* R1862  - AIF2TX1MIX Input 4 Source */
+       { 0x00000747, 0x0080 },   /* R1863  - AIF2TX1MIX Input 4 Volume */
+       { 0x00000748, 0x0000 },   /* R1864  - AIF2TX2MIX Input 1 Source */
+       { 0x00000749, 0x0080 },   /* R1865  - AIF2TX2MIX Input 1 Volume */
+       { 0x0000074A, 0x0000 },   /* R1866  - AIF2TX2MIX Input 2 Source */
+       { 0x0000074B, 0x0080 },   /* R1867  - AIF2TX2MIX Input 2 Volume */
+       { 0x0000074C, 0x0000 },   /* R1868  - AIF2TX2MIX Input 3 Source */
+       { 0x0000074D, 0x0080 },   /* R1869  - AIF2TX2MIX Input 3 Volume */
+       { 0x0000074E, 0x0000 },   /* R1870  - AIF2TX2MIX Input 4 Source */
+       { 0x0000074F, 0x0080 },   /* R1871  - AIF2TX2MIX Input 4 Volume */
+       { 0x00000780, 0x0000 },   /* R1920  - AIF3TX1MIX Input 1 Source */
+       { 0x00000781, 0x0080 },   /* R1921  - AIF3TX1MIX Input 1 Volume */
+       { 0x00000782, 0x0000 },   /* R1922  - AIF3TX1MIX Input 2 Source */
+       { 0x00000783, 0x0080 },   /* R1923  - AIF3TX1MIX Input 2 Volume */
+       { 0x00000784, 0x0000 },   /* R1924  - AIF3TX1MIX Input 3 Source */
+       { 0x00000785, 0x0080 },   /* R1925  - AIF3TX1MIX Input 3 Volume */
+       { 0x00000786, 0x0000 },   /* R1926  - AIF3TX1MIX Input 4 Source */
+       { 0x00000787, 0x0080 },   /* R1927  - AIF3TX1MIX Input 4 Volume */
+       { 0x00000788, 0x0000 },   /* R1928  - AIF3TX2MIX Input 1 Source */
+       { 0x00000789, 0x0080 },   /* R1929  - AIF3TX2MIX Input 1 Volume */
+       { 0x0000078A, 0x0000 },   /* R1930  - AIF3TX2MIX Input 2 Source */
+       { 0x0000078B, 0x0080 },   /* R1931  - AIF3TX2MIX Input 2 Volume */
+       { 0x0000078C, 0x0000 },   /* R1932  - AIF3TX2MIX Input 3 Source */
+       { 0x0000078D, 0x0080 },   /* R1933  - AIF3TX2MIX Input 3 Volume */
+       { 0x0000078E, 0x0000 },   /* R1934  - AIF3TX2MIX Input 4 Source */
+       { 0x0000078F, 0x0080 },   /* R1935  - AIF3TX2MIX Input 4 Volume */
+       { 0x000007C0, 0x0000 },   /* R1984  - SLIMTX1MIX Input 1 Source */
+       { 0x000007C1, 0x0080 },   /* R1985  - SLIMTX1MIX Input 1 Volume */
+       { 0x000007C2, 0x0000 },   /* R1986  - SLIMTX1MIX Input 2 Source */
+       { 0x000007C3, 0x0080 },   /* R1987  - SLIMTX1MIX Input 2 Volume */
+       { 0x000007C4, 0x0000 },   /* R1988  - SLIMTX1MIX Input 3 Source */
+       { 0x000007C5, 0x0080 },   /* R1989  - SLIMTX1MIX Input 3 Volume */
+       { 0x000007C6, 0x0000 },   /* R1990  - SLIMTX1MIX Input 4 Source */
+       { 0x000007C7, 0x0080 },   /* R1991  - SLIMTX1MIX Input 4 Volume */
+       { 0x000007C8, 0x0000 },   /* R1992  - SLIMTX2MIX Input 1 Source */
+       { 0x000007C9, 0x0080 },   /* R1993  - SLIMTX2MIX Input 1 Volume */
+       { 0x000007CA, 0x0000 },   /* R1994  - SLIMTX2MIX Input 2 Source */
+       { 0x000007CB, 0x0080 },   /* R1995  - SLIMTX2MIX Input 2 Volume */
+       { 0x000007CC, 0x0000 },   /* R1996  - SLIMTX2MIX Input 3 Source */
+       { 0x000007CD, 0x0080 },   /* R1997  - SLIMTX2MIX Input 3 Volume */
+       { 0x000007CE, 0x0000 },   /* R1998  - SLIMTX2MIX Input 4 Source */
+       { 0x000007CF, 0x0080 },   /* R1999  - SLIMTX2MIX Input 4 Volume */
+       { 0x000007D0, 0x0000 },   /* R2000  - SLIMTX3MIX Input 1 Source */
+       { 0x000007D1, 0x0080 },   /* R2001  - SLIMTX3MIX Input 1 Volume */
+       { 0x000007D2, 0x0000 },   /* R2002  - SLIMTX3MIX Input 2 Source */
+       { 0x000007D3, 0x0080 },   /* R2003  - SLIMTX3MIX Input 2 Volume */
+       { 0x000007D4, 0x0000 },   /* R2004  - SLIMTX3MIX Input 3 Source */
+       { 0x000007D5, 0x0080 },   /* R2005  - SLIMTX3MIX Input 3 Volume */
+       { 0x000007D6, 0x0000 },   /* R2006  - SLIMTX3MIX Input 4 Source */
+       { 0x000007D7, 0x0080 },   /* R2007  - SLIMTX3MIX Input 4 Volume */
+       { 0x000007D8, 0x0000 },   /* R2008  - SLIMTX4MIX Input 1 Source */
+       { 0x000007D9, 0x0080 },   /* R2009  - SLIMTX4MIX Input 1 Volume */
+       { 0x000007DA, 0x0000 },   /* R2010  - SLIMTX4MIX Input 2 Source */
+       { 0x000007DB, 0x0080 },   /* R2011  - SLIMTX4MIX Input 2 Volume */
+       { 0x000007DC, 0x0000 },   /* R2012  - SLIMTX4MIX Input 3 Source */
+       { 0x000007DD, 0x0080 },   /* R2013  - SLIMTX4MIX Input 3 Volume */
+       { 0x000007DE, 0x0000 },   /* R2014  - SLIMTX4MIX Input 4 Source */
+       { 0x000007DF, 0x0080 },   /* R2015  - SLIMTX4MIX Input 4 Volume */
+       { 0x000007E0, 0x0000 },   /* R2016  - SLIMTX5MIX Input 1 Source */
+       { 0x000007E1, 0x0080 },   /* R2017  - SLIMTX5MIX Input 1 Volume */
+       { 0x000007E2, 0x0000 },   /* R2018  - SLIMTX5MIX Input 2 Source */
+       { 0x000007E3, 0x0080 },   /* R2019  - SLIMTX5MIX Input 2 Volume */
+       { 0x000007E4, 0x0000 },   /* R2020  - SLIMTX5MIX Input 3 Source */
+       { 0x000007E5, 0x0080 },   /* R2021  - SLIMTX5MIX Input 3 Volume */
+       { 0x000007E6, 0x0000 },   /* R2022  - SLIMTX5MIX Input 4 Source */
+       { 0x000007E7, 0x0080 },   /* R2023  - SLIMTX5MIX Input 4 Volume */
+       { 0x000007E8, 0x0000 },   /* R2024  - SLIMTX6MIX Input 1 Source */
+       { 0x000007E9, 0x0080 },   /* R2025  - SLIMTX6MIX Input 1 Volume */
+       { 0x000007EA, 0x0000 },   /* R2026  - SLIMTX6MIX Input 2 Source */
+       { 0x000007EB, 0x0080 },   /* R2027  - SLIMTX6MIX Input 2 Volume */
+       { 0x000007EC, 0x0000 },   /* R2028  - SLIMTX6MIX Input 3 Source */
+       { 0x000007ED, 0x0080 },   /* R2029  - SLIMTX6MIX Input 3 Volume */
+       { 0x000007EE, 0x0000 },   /* R2030  - SLIMTX6MIX Input 4 Source */
+       { 0x000007EF, 0x0080 },   /* R2031  - SLIMTX6MIX Input 4 Volume */
+       { 0x000007F0, 0x0000 },   /* R2032  - SLIMTX7MIX Input 1 Source */
+       { 0x000007F1, 0x0080 },   /* R2033  - SLIMTX7MIX Input 1 Volume */
+       { 0x000007F2, 0x0000 },   /* R2034  - SLIMTX7MIX Input 2 Source */
+       { 0x000007F3, 0x0080 },   /* R2035  - SLIMTX7MIX Input 2 Volume */
+       { 0x000007F4, 0x0000 },   /* R2036  - SLIMTX7MIX Input 3 Source */
+       { 0x000007F5, 0x0080 },   /* R2037  - SLIMTX7MIX Input 3 Volume */
+       { 0x000007F6, 0x0000 },   /* R2038  - SLIMTX7MIX Input 4 Source */
+       { 0x000007F7, 0x0080 },   /* R2039  - SLIMTX7MIX Input 4 Volume */
+       { 0x000007F8, 0x0000 },   /* R2040  - SLIMTX8MIX Input 1 Source */
+       { 0x000007F9, 0x0080 },   /* R2041  - SLIMTX8MIX Input 1 Volume */
+       { 0x000007FA, 0x0000 },   /* R2042  - SLIMTX8MIX Input 2 Source */
+       { 0x000007FB, 0x0080 },   /* R2043  - SLIMTX8MIX Input 2 Volume */
+       { 0x000007FC, 0x0000 },   /* R2044  - SLIMTX8MIX Input 3 Source */
+       { 0x000007FD, 0x0080 },   /* R2045  - SLIMTX8MIX Input 3 Volume */
+       { 0x000007FE, 0x0000 },   /* R2046  - SLIMTX8MIX Input 4 Source */
+       { 0x000007FF, 0x0080 },   /* R2047  - SLIMTX8MIX Input 4 Volume */
+       { 0x00000880, 0x0000 },   /* R2176  - EQ1MIX Input 1 Source */
+       { 0x00000881, 0x0080 },   /* R2177  - EQ1MIX Input 1 Volume */
+       { 0x00000882, 0x0000 },   /* R2178  - EQ1MIX Input 2 Source */
+       { 0x00000883, 0x0080 },   /* R2179  - EQ1MIX Input 2 Volume */
+       { 0x00000884, 0x0000 },   /* R2180  - EQ1MIX Input 3 Source */
+       { 0x00000885, 0x0080 },   /* R2181  - EQ1MIX Input 3 Volume */
+       { 0x00000886, 0x0000 },   /* R2182  - EQ1MIX Input 4 Source */
+       { 0x00000887, 0x0080 },   /* R2183  - EQ1MIX Input 4 Volume */
+       { 0x00000888, 0x0000 },   /* R2184  - EQ2MIX Input 1 Source */
+       { 0x00000889, 0x0080 },   /* R2185  - EQ2MIX Input 1 Volume */
+       { 0x0000088A, 0x0000 },   /* R2186  - EQ2MIX Input 2 Source */
+       { 0x0000088B, 0x0080 },   /* R2187  - EQ2MIX Input 2 Volume */
+       { 0x0000088C, 0x0000 },   /* R2188  - EQ2MIX Input 3 Source */
+       { 0x0000088D, 0x0080 },   /* R2189  - EQ2MIX Input 3 Volume */
+       { 0x0000088E, 0x0000 },   /* R2190  - EQ2MIX Input 4 Source */
+       { 0x0000088F, 0x0080 },   /* R2191  - EQ2MIX Input 4 Volume */
+       { 0x00000890, 0x0000 },   /* R2192  - EQ3MIX Input 1 Source */
+       { 0x00000891, 0x0080 },   /* R2193  - EQ3MIX Input 1 Volume */
+       { 0x00000892, 0x0000 },   /* R2194  - EQ3MIX Input 2 Source */
+       { 0x00000893, 0x0080 },   /* R2195  - EQ3MIX Input 2 Volume */
+       { 0x00000894, 0x0000 },   /* R2196  - EQ3MIX Input 3 Source */
+       { 0x00000895, 0x0080 },   /* R2197  - EQ3MIX Input 3 Volume */
+       { 0x00000896, 0x0000 },   /* R2198  - EQ3MIX Input 4 Source */
+       { 0x00000897, 0x0080 },   /* R2199  - EQ3MIX Input 4 Volume */
+       { 0x00000898, 0x0000 },   /* R2200  - EQ4MIX Input 1 Source */
+       { 0x00000899, 0x0080 },   /* R2201  - EQ4MIX Input 1 Volume */
+       { 0x0000089A, 0x0000 },   /* R2202  - EQ4MIX Input 2 Source */
+       { 0x0000089B, 0x0080 },   /* R2203  - EQ4MIX Input 2 Volume */
+       { 0x0000089C, 0x0000 },   /* R2204  - EQ4MIX Input 3 Source */
+       { 0x0000089D, 0x0080 },   /* R2205  - EQ4MIX Input 3 Volume */
+       { 0x0000089E, 0x0000 },   /* R2206  - EQ4MIX Input 4 Source */
+       { 0x0000089F, 0x0080 },   /* R2207  - EQ4MIX Input 4 Volume */
+       { 0x000008C0, 0x0000 },   /* R2240  - DRC1LMIX Input 1 Source */
+       { 0x000008C1, 0x0080 },   /* R2241  - DRC1LMIX Input 1 Volume */
+       { 0x000008C2, 0x0000 },   /* R2242  - DRC1LMIX Input 2 Source */
+       { 0x000008C3, 0x0080 },   /* R2243  - DRC1LMIX Input 2 Volume */
+       { 0x000008C4, 0x0000 },   /* R2244  - DRC1LMIX Input 3 Source */
+       { 0x000008C5, 0x0080 },   /* R2245  - DRC1LMIX Input 3 Volume */
+       { 0x000008C6, 0x0000 },   /* R2246  - DRC1LMIX Input 4 Source */
+       { 0x000008C7, 0x0080 },   /* R2247  - DRC1LMIX Input 4 Volume */
+       { 0x000008C8, 0x0000 },   /* R2248  - DRC1RMIX Input 1 Source */
+       { 0x000008C9, 0x0080 },   /* R2249  - DRC1RMIX Input 1 Volume */
+       { 0x000008CA, 0x0000 },   /* R2250  - DRC1RMIX Input 2 Source */
+       { 0x000008CB, 0x0080 },   /* R2251  - DRC1RMIX Input 2 Volume */
+       { 0x000008CC, 0x0000 },   /* R2252  - DRC1RMIX Input 3 Source */
+       { 0x000008CD, 0x0080 },   /* R2253  - DRC1RMIX Input 3 Volume */
+       { 0x000008CE, 0x0000 },   /* R2254  - DRC1RMIX Input 4 Source */
+       { 0x000008CF, 0x0080 },   /* R2255  - DRC1RMIX Input 4 Volume */
+       { 0x00000900, 0x0000 },   /* R2304  - HPLP1MIX Input 1 Source */
+       { 0x00000901, 0x0080 },   /* R2305  - HPLP1MIX Input 1 Volume */
+       { 0x00000902, 0x0000 },   /* R2306  - HPLP1MIX Input 2 Source */
+       { 0x00000903, 0x0080 },   /* R2307  - HPLP1MIX Input 2 Volume */
+       { 0x00000904, 0x0000 },   /* R2308  - HPLP1MIX Input 3 Source */
+       { 0x00000905, 0x0080 },   /* R2309  - HPLP1MIX Input 3 Volume */
+       { 0x00000906, 0x0000 },   /* R2310  - HPLP1MIX Input 4 Source */
+       { 0x00000907, 0x0080 },   /* R2311  - HPLP1MIX Input 4 Volume */
+       { 0x00000908, 0x0000 },   /* R2312  - HPLP2MIX Input 1 Source */
+       { 0x00000909, 0x0080 },   /* R2313  - HPLP2MIX Input 1 Volume */
+       { 0x0000090A, 0x0000 },   /* R2314  - HPLP2MIX Input 2 Source */
+       { 0x0000090B, 0x0080 },   /* R2315  - HPLP2MIX Input 2 Volume */
+       { 0x0000090C, 0x0000 },   /* R2316  - HPLP2MIX Input 3 Source */
+       { 0x0000090D, 0x0080 },   /* R2317  - HPLP2MIX Input 3 Volume */
+       { 0x0000090E, 0x0000 },   /* R2318  - HPLP2MIX Input 4 Source */
+       { 0x0000090F, 0x0080 },   /* R2319  - HPLP2MIX Input 4 Volume */
+       { 0x00000910, 0x0000 },   /* R2320  - HPLP3MIX Input 1 Source */
+       { 0x00000911, 0x0080 },   /* R2321  - HPLP3MIX Input 1 Volume */
+       { 0x00000912, 0x0000 },   /* R2322  - HPLP3MIX Input 2 Source */
+       { 0x00000913, 0x0080 },   /* R2323  - HPLP3MIX Input 2 Volume */
+       { 0x00000914, 0x0000 },   /* R2324  - HPLP3MIX Input 3 Source */
+       { 0x00000915, 0x0080 },   /* R2325  - HPLP3MIX Input 3 Volume */
+       { 0x00000916, 0x0000 },   /* R2326  - HPLP3MIX Input 4 Source */
+       { 0x00000917, 0x0080 },   /* R2327  - HPLP3MIX Input 4 Volume */
+       { 0x00000918, 0x0000 },   /* R2328  - HPLP4MIX Input 1 Source */
+       { 0x00000919, 0x0080 },   /* R2329  - HPLP4MIX Input 1 Volume */
+       { 0x0000091A, 0x0000 },   /* R2330  - HPLP4MIX Input 2 Source */
+       { 0x0000091B, 0x0080 },   /* R2331  - HPLP4MIX Input 2 Volume */
+       { 0x0000091C, 0x0000 },   /* R2332  - HPLP4MIX Input 3 Source */
+       { 0x0000091D, 0x0080 },   /* R2333  - HPLP4MIX Input 3 Volume */
+       { 0x0000091E, 0x0000 },   /* R2334  - HPLP4MIX Input 4 Source */
+       { 0x0000091F, 0x0080 },   /* R2335  - HPLP4MIX Input 4 Volume */
+       { 0x00000940, 0x0000 },   /* R2368  - DSP1LMIX Input 1 Source */
+       { 0x00000941, 0x0080 },   /* R2369  - DSP1LMIX Input 1 Volume */
+       { 0x00000942, 0x0000 },   /* R2370  - DSP1LMIX Input 2 Source */
+       { 0x00000943, 0x0080 },   /* R2371  - DSP1LMIX Input 2 Volume */
+       { 0x00000944, 0x0000 },   /* R2372  - DSP1LMIX Input 3 Source */
+       { 0x00000945, 0x0080 },   /* R2373  - DSP1LMIX Input 3 Volume */
+       { 0x00000946, 0x0000 },   /* R2374  - DSP1LMIX Input 4 Source */
+       { 0x00000947, 0x0080 },   /* R2375  - DSP1LMIX Input 4 Volume */
+       { 0x00000948, 0x0000 },   /* R2376  - DSP1RMIX Input 1 Source */
+       { 0x00000949, 0x0080 },   /* R2377  - DSP1RMIX Input 1 Volume */
+       { 0x0000094A, 0x0000 },   /* R2378  - DSP1RMIX Input 2 Source */
+       { 0x0000094B, 0x0080 },   /* R2379  - DSP1RMIX Input 2 Volume */
+       { 0x0000094C, 0x0000 },   /* R2380  - DSP1RMIX Input 3 Source */
+       { 0x0000094D, 0x0080 },   /* R2381  - DSP1RMIX Input 3 Volume */
+       { 0x0000094E, 0x0000 },   /* R2382  - DSP1RMIX Input 4 Source */
+       { 0x0000094F, 0x0080 },   /* R2383  - DSP1RMIX Input 4 Volume */
+       { 0x00000950, 0x0000 },   /* R2384  - DSP1AUX1MIX Input 1 Source */
+       { 0x00000958, 0x0000 },   /* R2392  - DSP1AUX2MIX Input 1 Source */
+       { 0x00000960, 0x0000 },   /* R2400  - DSP1AUX3MIX Input 1 Source */
+       { 0x00000968, 0x0000 },   /* R2408  - DSP1AUX4MIX Input 1 Source */
+       { 0x00000970, 0x0000 },   /* R2416  - DSP1AUX5MIX Input 1 Source */
+       { 0x00000978, 0x0000 },   /* R2424  - DSP1AUX6MIX Input 1 Source */
+       { 0x00000A80, 0x0000 },   /* R2688  - ASRC1LMIX Input 1 Source */
+       { 0x00000A88, 0x0000 },   /* R2696  - ASRC1RMIX Input 1 Source */
+       { 0x00000A90, 0x0000 },   /* R2704  - ASRC2LMIX Input 1 Source */
+       { 0x00000A98, 0x0000 },   /* R2712  - ASRC2RMIX Input 1 Source */
+       { 0x00000B00, 0x0000 },   /* R2816  - ISRC1DEC1MIX Input 1 Source */
+       { 0x00000B08, 0x0000 },   /* R2824  - ISRC1DEC2MIX Input 1 Source */
+       { 0x00000B20, 0x0000 },   /* R2848  - ISRC1INT1MIX Input 1 Source */
+       { 0x00000B28, 0x0000 },   /* R2856  - ISRC1INT2MIX Input 1 Source */
+       { 0x00000B40, 0x0000 },   /* R2880  - ISRC2DEC1MIX Input 1 Source */
+       { 0x00000B48, 0x0000 },   /* R2888  - ISRC2DEC2MIX Input 1 Source */
+       { 0x00000B60, 0x0000 },   /* R2912  - ISRC2INT1MIX Input 1 Source */
+       { 0x00000B68, 0x0000 },   /* R2920  - ISRC2INT2MIX Input 1 Source */
+       { 0x00000C00, 0xA101 },   /* R3072  - GPIO1 CTRL */
+       { 0x00000C01, 0xA101 },   /* R3073  - GPIO2 CTRL */
+       { 0x00000C02, 0xA101 },   /* R3074  - GPIO3 CTRL */
+       { 0x00000C03, 0xA101 },   /* R3075  - GPIO4 CTRL */
+       { 0x00000C04, 0xA101 },   /* R3076  - GPIO5 CTRL */
+       { 0x00000C0F, 0x0400 },   /* R3087  - IRQ CTRL 1 */
+       { 0x00000C10, 0x1000 },   /* R3088  - GPIO Debounce Config */
+       { 0x00000C20, 0x8002 },   /* R3104  - Misc Pad Ctrl 1 */
        { 0x00000C21, 0x0001 },   /* R3105  - Misc Pad Ctrl 2 */
-       { 0x00000C22, 0x0000 },   /* R3106  - Misc Pad Ctrl 3 */ 
-       { 0x00000C23, 0x0000 },   /* R3107  - Misc Pad Ctrl 4 */ 
-       { 0x00000C24, 0x0000 },   /* R3108  - Misc Pad Ctrl 5 */ 
-       { 0x00000C25, 0x0000 },   /* R3109  - Misc Pad Ctrl 6 */ 
-       { 0x00000D08, 0xFFFF },   /* R3336  - Interrupt Status 1 Mask */ 
-       { 0x00000D09, 0xFFFF },   /* R3337  - Interrupt Status 2 Mask */ 
-       { 0x00000D0A, 0xFFFF },   /* R3338  - Interrupt Status 3 Mask */ 
-       { 0x00000D0B, 0xFFFF },   /* R3339  - Interrupt Status 4 Mask */ 
-       { 0x00000D0C, 0xFEFF },   /* R3340  - Interrupt Status 5 Mask */ 
-       { 0x00000D0F, 0x0000 },   /* R3343  - Interrupt Control */ 
-       { 0x00000D18, 0xFFFF },   /* R3352  - IRQ2 Status 1 Mask */ 
-       { 0x00000D19, 0xFFFF },   /* R3353  - IRQ2 Status 2 Mask */ 
-       { 0x00000D1A, 0xFFFF },   /* R3354  - IRQ2 Status 3 Mask */ 
-       { 0x00000D1B, 0xFFFF },   /* R3355  - IRQ2 Status 4 Mask */ 
-       { 0x00000D1C, 0xFFFF },   /* R3356  - IRQ2 Status 5 Mask */ 
-       { 0x00000D1F, 0x0000 },   /* R3359  - IRQ2 Control */ 
+       { 0x00000C22, 0x0000 },   /* R3106  - Misc Pad Ctrl 3 */
+       { 0x00000C23, 0x0000 },   /* R3107  - Misc Pad Ctrl 4 */
+       { 0x00000C24, 0x0000 },   /* R3108  - Misc Pad Ctrl 5 */
+       { 0x00000C25, 0x0000 },   /* R3109  - Misc Pad Ctrl 6 */
+       { 0x00000D08, 0xFFFF },   /* R3336  - Interrupt Status 1 Mask */
+       { 0x00000D09, 0xFFFF },   /* R3337  - Interrupt Status 2 Mask */
+       { 0x00000D0A, 0xFFFF },   /* R3338  - Interrupt Status 3 Mask */
+       { 0x00000D0B, 0xFFFF },   /* R3339  - Interrupt Status 4 Mask */
+       { 0x00000D0C, 0xFEFF },   /* R3340  - Interrupt Status 5 Mask */
+       { 0x00000D0F, 0x0000 },   /* R3343  - Interrupt Control */
+       { 0x00000D18, 0xFFFF },   /* R3352  - IRQ2 Status 1 Mask */
+       { 0x00000D19, 0xFFFF },   /* R3353  - IRQ2 Status 2 Mask */
+       { 0x00000D1A, 0xFFFF },   /* R3354  - IRQ2 Status 3 Mask */
+       { 0x00000D1B, 0xFFFF },   /* R3355  - IRQ2 Status 4 Mask */
+       { 0x00000D1C, 0xFFFF },   /* R3356  - IRQ2 Status 5 Mask */
+       { 0x00000D1F, 0x0000 },   /* R3359  - IRQ2 Control */
        { 0x00000D41, 0x0000 },   /* R3393  - ADSP2 IRQ0 */
-       { 0x00000D53, 0xFFFF },   /* R3411  - AOD IRQ Mask IRQ1 */ 
-       { 0x00000D54, 0xFFFF },   /* R3412  - AOD IRQ Mask IRQ2 */ 
-       { 0x00000D56, 0x0000 },   /* R3414  - Jack detect debounce */ 
-       { 0x00000E00, 0x0000 },   /* R3584  - FX_Ctrl1 */ 
-       { 0x00000E10, 0x6318 },   /* R3600  - EQ1_1 */ 
-       { 0x00000E11, 0x6300 },   /* R3601  - EQ1_2 */ 
-       { 0x00000E12, 0x0FC8 },   /* R3602  - EQ1_3 */ 
-       { 0x00000E13, 0x03FE },   /* R3603  - EQ1_4 */ 
-       { 0x00000E14, 0x00E0 },   /* R3604  - EQ1_5 */ 
-       { 0x00000E15, 0x1EC4 },   /* R3605  - EQ1_6 */ 
-       { 0x00000E16, 0xF136 },   /* R3606  - EQ1_7 */ 
-       { 0x00000E17, 0x0409 },   /* R3607  - EQ1_8 */ 
-       { 0x00000E18, 0x04CC },   /* R3608  - EQ1_9 */ 
-       { 0x00000E19, 0x1C9B },   /* R3609  - EQ1_10 */ 
-       { 0x00000E1A, 0xF337 },   /* R3610  - EQ1_11 */ 
-       { 0x00000E1B, 0x040B },   /* R3611  - EQ1_12 */ 
-       { 0x00000E1C, 0x0CBB },   /* R3612  - EQ1_13 */ 
-       { 0x00000E1D, 0x16F8 },   /* R3613  - EQ1_14 */ 
-       { 0x00000E1E, 0xF7D9 },   /* R3614  - EQ1_15 */ 
-       { 0x00000E1F, 0x040A },   /* R3615  - EQ1_16 */ 
-       { 0x00000E20, 0x1F14 },   /* R3616  - EQ1_17 */ 
-       { 0x00000E21, 0x058C },   /* R3617  - EQ1_18 */ 
-       { 0x00000E22, 0x0563 },   /* R3618  - EQ1_19 */ 
-       { 0x00000E23, 0x4000 },   /* R3619  - EQ1_20 */ 
-       { 0x00000E24, 0x0B75 },   /* R3620  - EQ1_21 */ 
-       { 0x00000E26, 0x6318 },   /* R3622  - EQ2_1 */ 
-       { 0x00000E27, 0x6300 },   /* R3623  - EQ2_2 */ 
-       { 0x00000E28, 0x0FC8 },   /* R3624  - EQ2_3 */ 
-       { 0x00000E29, 0x03FE },   /* R3625  - EQ2_4 */ 
-       { 0x00000E2A, 0x00E0 },   /* R3626  - EQ2_5 */ 
-       { 0x00000E2B, 0x1EC4 },   /* R3627  - EQ2_6 */ 
-       { 0x00000E2C, 0xF136 },   /* R3628  - EQ2_7 */ 
-       { 0x00000E2D, 0x0409 },   /* R3629  - EQ2_8 */ 
-       { 0x00000E2E, 0x04CC },   /* R3630  - EQ2_9 */ 
-       { 0x00000E2F, 0x1C9B },   /* R3631  - EQ2_10 */ 
-       { 0x00000E30, 0xF337 },   /* R3632  - EQ2_11 */ 
-       { 0x00000E31, 0x040B },   /* R3633  - EQ2_12 */ 
-       { 0x00000E32, 0x0CBB },   /* R3634  - EQ2_13 */ 
-       { 0x00000E33, 0x16F8 },   /* R3635  - EQ2_14 */ 
-       { 0x00000E34, 0xF7D9 },   /* R3636  - EQ2_15 */ 
-       { 0x00000E35, 0x040A },   /* R3637  - EQ2_16 */ 
-       { 0x00000E36, 0x1F14 },   /* R3638  - EQ2_17 */ 
-       { 0x00000E37, 0x058C },   /* R3639  - EQ2_18 */ 
-       { 0x00000E38, 0x0563 },   /* R3640  - EQ2_19 */ 
-       { 0x00000E39, 0x4000 },   /* R3641  - EQ2_20 */ 
-       { 0x00000E3A, 0x0B75 },   /* R3642  - EQ2_21 */ 
-       { 0x00000E3C, 0x6318 },   /* R3644  - EQ3_1 */ 
-       { 0x00000E3D, 0x6300 },   /* R3645  - EQ3_2 */ 
-       { 0x00000E3E, 0x0FC8 },   /* R3646  - EQ3_3 */ 
-       { 0x00000E3F, 0x03FE },   /* R3647  - EQ3_4 */ 
-       { 0x00000E40, 0x00E0 },   /* R3648  - EQ3_5 */ 
-       { 0x00000E41, 0x1EC4 },   /* R3649  - EQ3_6 */ 
-       { 0x00000E42, 0xF136 },   /* R3650  - EQ3_7 */ 
-       { 0x00000E43, 0x0409 },   /* R3651  - EQ3_8 */ 
-       { 0x00000E44, 0x04CC },   /* R3652  - EQ3_9 */ 
-       { 0x00000E45, 0x1C9B },   /* R3653  - EQ3_10 */ 
-       { 0x00000E46, 0xF337 },   /* R3654  - EQ3_11 */ 
-       { 0x00000E47, 0x040B },   /* R3655  - EQ3_12 */ 
-       { 0x00000E48, 0x0CBB },   /* R3656  - EQ3_13 */ 
-       { 0x00000E49, 0x16F8 },   /* R3657  - EQ3_14 */ 
-       { 0x00000E4A, 0xF7D9 },   /* R3658  - EQ3_15 */ 
-       { 0x00000E4B, 0x040A },   /* R3659  - EQ3_16 */ 
-       { 0x00000E4C, 0x1F14 },   /* R3660  - EQ3_17 */ 
-       { 0x00000E4D, 0x058C },   /* R3661  - EQ3_18 */ 
-       { 0x00000E4E, 0x0563 },   /* R3662  - EQ3_19 */ 
-       { 0x00000E4F, 0x4000 },   /* R3663  - EQ3_20 */ 
-       { 0x00000E50, 0x0B75 },   /* R3664  - EQ3_21 */ 
-       { 0x00000E52, 0x6318 },   /* R3666  - EQ4_1 */ 
-       { 0x00000E53, 0x6300 },   /* R3667  - EQ4_2 */ 
-       { 0x00000E54, 0x0FC8 },   /* R3668  - EQ4_3 */ 
-       { 0x00000E55, 0x03FE },   /* R3669  - EQ4_4 */ 
-       { 0x00000E56, 0x00E0 },   /* R3670  - EQ4_5 */ 
-       { 0x00000E57, 0x1EC4 },   /* R3671  - EQ4_6 */ 
-       { 0x00000E58, 0xF136 },   /* R3672  - EQ4_7 */ 
-       { 0x00000E59, 0x0409 },   /* R3673  - EQ4_8 */ 
-       { 0x00000E5A, 0x04CC },   /* R3674  - EQ4_9 */ 
-       { 0x00000E5B, 0x1C9B },   /* R3675  - EQ4_10 */ 
-       { 0x00000E5C, 0xF337 },   /* R3676  - EQ4_11 */ 
-       { 0x00000E5D, 0x040B },   /* R3677  - EQ4_12 */ 
-       { 0x00000E5E, 0x0CBB },   /* R3678  - EQ4_13 */ 
-       { 0x00000E5F, 0x16F8 },   /* R3679  - EQ4_14 */ 
-       { 0x00000E60, 0xF7D9 },   /* R3680  - EQ4_15 */ 
-       { 0x00000E61, 0x040A },   /* R3681  - EQ4_16 */ 
-       { 0x00000E62, 0x1F14 },   /* R3682  - EQ4_17 */ 
-       { 0x00000E63, 0x058C },   /* R3683  - EQ4_18 */ 
-       { 0x00000E64, 0x0563 },   /* R3684  - EQ4_19 */ 
-       { 0x00000E65, 0x4000 },   /* R3685  - EQ4_20 */ 
-       { 0x00000E66, 0x0B75 },   /* R3686  - EQ4_21 */ 
-       { 0x00000E80, 0x0018 },   /* R3712  - DRC1 ctrl1 */ 
-       { 0x00000E81, 0x0933 },   /* R3713  - DRC1 ctrl2 */ 
-       { 0x00000E82, 0x0018 },   /* R3714  - DRC1 ctrl3 */ 
-       { 0x00000E83, 0x0000 },   /* R3715  - DRC1 ctrl4 */ 
-       { 0x00000E84, 0x0000 },   /* R3716  - DRC1 ctrl5 */ 
-       { 0x00000EC0, 0x0000 },   /* R3776  - HPLPF1_1 */ 
-       { 0x00000EC1, 0x0000 },   /* R3777  - HPLPF1_2 */ 
-       { 0x00000EC4, 0x0000 },   /* R3780  - HPLPF2_1 */ 
-       { 0x00000EC5, 0x0000 },   /* R3781  - HPLPF2_2 */ 
-       { 0x00000EC8, 0x0000 },   /* R3784  - HPLPF3_1 */ 
-       { 0x00000EC9, 0x0000 },   /* R3785  - HPLPF3_2 */ 
-       { 0x00000ECC, 0x0000 },   /* R3788  - HPLPF4_1 */ 
-       { 0x00000ECD, 0x0000 },   /* R3789  - HPLPF4_2 */ 
-       { 0x00000EE0, 0x0000 },   /* R3808  - ASRC_ENABLE */ 
-       { 0x00000EE2, 0x0000 },   /* R3810  - ASRC_RATE1 */ 
+       { 0x00000D53, 0xFFFF },   /* R3411  - AOD IRQ Mask IRQ1 */
+       { 0x00000D54, 0xFFFF },   /* R3412  - AOD IRQ Mask IRQ2 */
+       { 0x00000D56, 0x0000 },   /* R3414  - Jack detect debounce */
+       { 0x00000E00, 0x0000 },   /* R3584  - FX_Ctrl1 */
+       { 0x00000E10, 0x6318 },   /* R3600  - EQ1_1 */
+       { 0x00000E11, 0x6300 },   /* R3601  - EQ1_2 */
+       { 0x00000E12, 0x0FC8 },   /* R3602  - EQ1_3 */
+       { 0x00000E13, 0x03FE },   /* R3603  - EQ1_4 */
+       { 0x00000E14, 0x00E0 },   /* R3604  - EQ1_5 */
+       { 0x00000E15, 0x1EC4 },   /* R3605  - EQ1_6 */
+       { 0x00000E16, 0xF136 },   /* R3606  - EQ1_7 */
+       { 0x00000E17, 0x0409 },   /* R3607  - EQ1_8 */
+       { 0x00000E18, 0x04CC },   /* R3608  - EQ1_9 */
+       { 0x00000E19, 0x1C9B },   /* R3609  - EQ1_10 */
+       { 0x00000E1A, 0xF337 },   /* R3610  - EQ1_11 */
+       { 0x00000E1B, 0x040B },   /* R3611  - EQ1_12 */
+       { 0x00000E1C, 0x0CBB },   /* R3612  - EQ1_13 */
+       { 0x00000E1D, 0x16F8 },   /* R3613  - EQ1_14 */
+       { 0x00000E1E, 0xF7D9 },   /* R3614  - EQ1_15 */
+       { 0x00000E1F, 0x040A },   /* R3615  - EQ1_16 */
+       { 0x00000E20, 0x1F14 },   /* R3616  - EQ1_17 */
+       { 0x00000E21, 0x058C },   /* R3617  - EQ1_18 */
+       { 0x00000E22, 0x0563 },   /* R3618  - EQ1_19 */
+       { 0x00000E23, 0x4000 },   /* R3619  - EQ1_20 */
+       { 0x00000E24, 0x0B75 },   /* R3620  - EQ1_21 */
+       { 0x00000E26, 0x6318 },   /* R3622  - EQ2_1 */
+       { 0x00000E27, 0x6300 },   /* R3623  - EQ2_2 */
+       { 0x00000E28, 0x0FC8 },   /* R3624  - EQ2_3 */
+       { 0x00000E29, 0x03FE },   /* R3625  - EQ2_4 */
+       { 0x00000E2A, 0x00E0 },   /* R3626  - EQ2_5 */
+       { 0x00000E2B, 0x1EC4 },   /* R3627  - EQ2_6 */
+       { 0x00000E2C, 0xF136 },   /* R3628  - EQ2_7 */
+       { 0x00000E2D, 0x0409 },   /* R3629  - EQ2_8 */
+       { 0x00000E2E, 0x04CC },   /* R3630  - EQ2_9 */
+       { 0x00000E2F, 0x1C9B },   /* R3631  - EQ2_10 */
+       { 0x00000E30, 0xF337 },   /* R3632  - EQ2_11 */
+       { 0x00000E31, 0x040B },   /* R3633  - EQ2_12 */
+       { 0x00000E32, 0x0CBB },   /* R3634  - EQ2_13 */
+       { 0x00000E33, 0x16F8 },   /* R3635  - EQ2_14 */
+       { 0x00000E34, 0xF7D9 },   /* R3636  - EQ2_15 */
+       { 0x00000E35, 0x040A },   /* R3637  - EQ2_16 */
+       { 0x00000E36, 0x1F14 },   /* R3638  - EQ2_17 */
+       { 0x00000E37, 0x058C },   /* R3639  - EQ2_18 */
+       { 0x00000E38, 0x0563 },   /* R3640  - EQ2_19 */
+       { 0x00000E39, 0x4000 },   /* R3641  - EQ2_20 */
+       { 0x00000E3A, 0x0B75 },   /* R3642  - EQ2_21 */
+       { 0x00000E3C, 0x6318 },   /* R3644  - EQ3_1 */
+       { 0x00000E3D, 0x6300 },   /* R3645  - EQ3_2 */
+       { 0x00000E3E, 0x0FC8 },   /* R3646  - EQ3_3 */
+       { 0x00000E3F, 0x03FE },   /* R3647  - EQ3_4 */
+       { 0x00000E40, 0x00E0 },   /* R3648  - EQ3_5 */
+       { 0x00000E41, 0x1EC4 },   /* R3649  - EQ3_6 */
+       { 0x00000E42, 0xF136 },   /* R3650  - EQ3_7 */
+       { 0x00000E43, 0x0409 },   /* R3651  - EQ3_8 */
+       { 0x00000E44, 0x04CC },   /* R3652  - EQ3_9 */
+       { 0x00000E45, 0x1C9B },   /* R3653  - EQ3_10 */
+       { 0x00000E46, 0xF337 },   /* R3654  - EQ3_11 */
+       { 0x00000E47, 0x040B },   /* R3655  - EQ3_12 */
+       { 0x00000E48, 0x0CBB },   /* R3656  - EQ3_13 */
+       { 0x00000E49, 0x16F8 },   /* R3657  - EQ3_14 */
+       { 0x00000E4A, 0xF7D9 },   /* R3658  - EQ3_15 */
+       { 0x00000E4B, 0x040A },   /* R3659  - EQ3_16 */
+       { 0x00000E4C, 0x1F14 },   /* R3660  - EQ3_17 */
+       { 0x00000E4D, 0x058C },   /* R3661  - EQ3_18 */
+       { 0x00000E4E, 0x0563 },   /* R3662  - EQ3_19 */
+       { 0x00000E4F, 0x4000 },   /* R3663  - EQ3_20 */
+       { 0x00000E50, 0x0B75 },   /* R3664  - EQ3_21 */
+       { 0x00000E52, 0x6318 },   /* R3666  - EQ4_1 */
+       { 0x00000E53, 0x6300 },   /* R3667  - EQ4_2 */
+       { 0x00000E54, 0x0FC8 },   /* R3668  - EQ4_3 */
+       { 0x00000E55, 0x03FE },   /* R3669  - EQ4_4 */
+       { 0x00000E56, 0x00E0 },   /* R3670  - EQ4_5 */
+       { 0x00000E57, 0x1EC4 },   /* R3671  - EQ4_6 */
+       { 0x00000E58, 0xF136 },   /* R3672  - EQ4_7 */
+       { 0x00000E59, 0x0409 },   /* R3673  - EQ4_8 */
+       { 0x00000E5A, 0x04CC },   /* R3674  - EQ4_9 */
+       { 0x00000E5B, 0x1C9B },   /* R3675  - EQ4_10 */
+       { 0x00000E5C, 0xF337 },   /* R3676  - EQ4_11 */
+       { 0x00000E5D, 0x040B },   /* R3677  - EQ4_12 */
+       { 0x00000E5E, 0x0CBB },   /* R3678  - EQ4_13 */
+       { 0x00000E5F, 0x16F8 },   /* R3679  - EQ4_14 */
+       { 0x00000E60, 0xF7D9 },   /* R3680  - EQ4_15 */
+       { 0x00000E61, 0x040A },   /* R3681  - EQ4_16 */
+       { 0x00000E62, 0x1F14 },   /* R3682  - EQ4_17 */
+       { 0x00000E63, 0x058C },   /* R3683  - EQ4_18 */
+       { 0x00000E64, 0x0563 },   /* R3684  - EQ4_19 */
+       { 0x00000E65, 0x4000 },   /* R3685  - EQ4_20 */
+       { 0x00000E66, 0x0B75 },   /* R3686  - EQ4_21 */
+       { 0x00000E80, 0x0018 },   /* R3712  - DRC1 ctrl1 */
+       { 0x00000E81, 0x0933 },   /* R3713  - DRC1 ctrl2 */
+       { 0x00000E82, 0x0018 },   /* R3714  - DRC1 ctrl3 */
+       { 0x00000E83, 0x0000 },   /* R3715  - DRC1 ctrl4 */
+       { 0x00000E84, 0x0000 },   /* R3716  - DRC1 ctrl5 */
+       { 0x00000EC0, 0x0000 },   /* R3776  - HPLPF1_1 */
+       { 0x00000EC1, 0x0000 },   /* R3777  - HPLPF1_2 */
+       { 0x00000EC4, 0x0000 },   /* R3780  - HPLPF2_1 */
+       { 0x00000EC5, 0x0000 },   /* R3781  - HPLPF2_2 */
+       { 0x00000EC8, 0x0000 },   /* R3784  - HPLPF3_1 */
+       { 0x00000EC9, 0x0000 },   /* R3785  - HPLPF3_2 */
+       { 0x00000ECC, 0x0000 },   /* R3788  - HPLPF4_1 */
+       { 0x00000ECD, 0x0000 },   /* R3789  - HPLPF4_2 */
+       { 0x00000EE0, 0x0000 },   /* R3808  - ASRC_ENABLE */
+       { 0x00000EE2, 0x0000 },   /* R3810  - ASRC_RATE1 */
        { 0x00000EE3, 0x4000 },   /* R3811  - ASRC_RATE2 */
-       { 0x00000EF0, 0x0000 },   /* R3824  - ISRC 1 CTRL 1 */ 
-       { 0x00000EF1, 0x0000 },   /* R3825  - ISRC 1 CTRL 2 */ 
-       { 0x00000EF2, 0x0000 },   /* R3826  - ISRC 1 CTRL 3 */ 
-       { 0x00000EF3, 0x0000 },   /* R3827  - ISRC 2 CTRL 1 */ 
-       { 0x00000EF4, 0x0000 },   /* R3828  - ISRC 2 CTRL 2 */ 
-       { 0x00000EF5, 0x0000 },   /* R3829  - ISRC 2 CTRL 3 */ 
-       { 0x00001100, 0x0010 },   /* R4352  - DSP1 Control 1 */ 
+       { 0x00000EF0, 0x0000 },   /* R3824  - ISRC 1 CTRL 1 */
+       { 0x00000EF1, 0x0000 },   /* R3825  - ISRC 1 CTRL 2 */
+       { 0x00000EF2, 0x0000 },   /* R3826  - ISRC 1 CTRL 3 */
+       { 0x00000EF3, 0x0000 },   /* R3827  - ISRC 2 CTRL 1 */
+       { 0x00000EF4, 0x0000 },   /* R3828  - ISRC 2 CTRL 2 */
+       { 0x00000EF5, 0x0000 },   /* R3829  - ISRC 2 CTRL 3 */
+       { 0x00001100, 0x0010 },   /* R4352  - DSP1 Control 1 */
 };
 
 static bool wm5102_readable_register(struct device *dev, unsigned int reg)
index 8588dbad330119149ad112c0bf493e1c979d59a3..953d0790ffd566e967058f7eeb640ff51377cf45 100644 (file)
@@ -406,8 +406,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err;
        }
 
-       ret = regulator_bulk_enable(wm8994->num_supplies,
-                                   wm8994->supplies);
+       ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
                goto err_regulator_free;
@@ -612,8 +611,7 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
 {
        pm_runtime_disable(wm8994->dev);
        wm8994_irq_exit(wm8994);
-       regulator_bulk_disable(wm8994->num_supplies,
-                              wm8994->supplies);
+       regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
        regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
        mfd_remove_devices(wm8994->dev);
 }
index d5dc80c48b4cb36a55c54a2383ce9812ae068260..b3323c0697f6239ebbfe757137cde8352fe3c480 100644 (file)
@@ -22,9 +22,8 @@ void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns)
 {
        struct nd_namespace_common *ndns = *_ndns;
 
-       dev_WARN_ONCE(dev, !mutex_is_locked(&ndns->dev.mutex)
-                       || ndns->claim != dev,
-                       "%s: invalid claim\n", __func__);
+       lockdep_assert_held(&ndns->dev.mutex);
+       dev_WARN_ONCE(dev, ndns->claim != dev, "%s: invalid claim\n", __func__);
        ndns->claim = NULL;
        *_ndns = NULL;
        put_device(&ndns->dev);
@@ -49,9 +48,8 @@ bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach,
 {
        if (attach->claim)
                return false;
-       dev_WARN_ONCE(dev, !mutex_is_locked(&attach->dev.mutex)
-                       || *_ndns,
-                       "%s: invalid claim\n", __func__);
+       lockdep_assert_held(&attach->dev.mutex);
+       dev_WARN_ONCE(dev, *_ndns, "%s: invalid claim\n", __func__);
        attach->claim = dev;
        *_ndns = attach;
        get_device(&attach->dev);
@@ -226,6 +224,12 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
                resource_size_t offset, void *buf, size_t size, int rw)
 {
        struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
+       unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
+       sector_t sector = offset >> 9;
+       int rc = 0;
+
+       if (unlikely(!size))
+               return 0;
 
        if (unlikely(offset + size > nsio->size)) {
                dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n");
@@ -233,17 +237,31 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
        }
 
        if (rw == READ) {
-               unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
-
-               if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align)))
+               if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align)))
                        return -EIO;
                return memcpy_from_pmem(buf, nsio->addr + offset, size);
-       } else {
-               memcpy_to_pmem(nsio->addr + offset, buf, size);
-               nvdimm_flush(to_nd_region(ndns->dev.parent));
        }
 
-       return 0;
+       if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) {
+               if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) {
+                       long cleared;
+
+                       cleared = nvdimm_clear_poison(&ndns->dev, offset, size);
+                       if (cleared < size)
+                               rc = -EIO;
+                       if (cleared > 0 && cleared / 512) {
+                               cleared /= 512;
+                               badblocks_clear(&nsio->bb, sector, cleared);
+                       }
+                       invalidate_pmem(nsio->addr + offset, size);
+               } else
+                       rc = -EIO;
+       }
+
+       memcpy_to_pmem(nsio->addr + offset, buf, size);
+       nvdimm_flush(to_nd_region(ndns->dev.parent));
+
+       return rc;
 }
 
 int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
@@ -253,7 +271,7 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)
 
        nsio->size = resource_size(res);
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
-                               dev_name(dev))) {
+                               dev_name(&ndns->dev))) {
                dev_warn(dev, "could not reserve region %pR\n", res);
                return -EBUSY;
        }
index 7ceba08774b690dbda57f667e223b3b0a180dd09..9303cfeb8bee507c171c2060fb7602e7b0519267 100644 (file)
@@ -317,35 +317,6 @@ ssize_t nd_sector_size_store(struct device *dev, const char *buf,
        }
 }
 
-void __nd_iostat_start(struct bio *bio, unsigned long *start)
-{
-       struct gendisk *disk = bio->bi_bdev->bd_disk;
-       const int rw = bio_data_dir(bio);
-       int cpu = part_stat_lock();
-
-       *start = jiffies;
-       part_round_stats(cpu, &disk->part0);
-       part_stat_inc(cpu, &disk->part0, ios[rw]);
-       part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
-       part_inc_in_flight(&disk->part0, rw);
-       part_stat_unlock();
-}
-EXPORT_SYMBOL(__nd_iostat_start);
-
-void nd_iostat_end(struct bio *bio, unsigned long start)
-{
-       struct gendisk *disk = bio->bi_bdev->bd_disk;
-       unsigned long duration = jiffies - start;
-       const int rw = bio_data_dir(bio);
-       int cpu = part_stat_lock();
-
-       part_stat_add(cpu, &disk->part0, ticks[rw], duration);
-       part_round_stats(cpu, &disk->part0);
-       part_dec_in_flight(&disk->part0, rw);
-       part_stat_unlock();
-}
-EXPORT_SYMBOL(nd_iostat_end);
-
 static ssize_t commands_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
index 619834e144d1e65e2314cde9356c86cff44d5053..ee0b412827bfb43fc739d5e03e873f12254517fa 100644 (file)
@@ -64,6 +64,8 @@ static int nvdimm_probe(struct device *dev)
        nd_label_copy(ndd, to_next_namespace_index(ndd),
                        to_current_namespace_index(ndd));
        rc = nd_label_reserve_dpa(ndd);
+       if (ndd->ns_current >= 0)
+               nvdimm_set_aliasing(dev);
        nvdimm_bus_unlock(dev);
 
        if (rc)
index d614493ad5acb849037d22bcc44fd78c0e80e1a3..0eedc49e0d473ed36b5ef9832760aa8498b9f146 100644 (file)
@@ -184,6 +184,13 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
        return rc;
 }
 
+void nvdimm_set_aliasing(struct device *dev)
+{
+       struct nvdimm *nvdimm = to_nvdimm(dev);
+
+       nvdimm->flags |= NDD_ALIASING;
+}
+
 static void nvdimm_release(struct device *dev)
 {
        struct nvdimm *nvdimm = to_nvdimm(dev);
index 11ea90120542dcbec8410147efca7a502eea9a77..6f9a6ffd7cde25f3e4714b2035eb519db1099fd8 100644 (file)
@@ -84,18 +84,8 @@ static struct platform_driver e820_pmem_driver = {
        },
 };
 
-static __init int e820_pmem_init(void)
-{
-       return platform_driver_register(&e820_pmem_driver);
-}
-
-static __exit void e820_pmem_exit(void)
-{
-       platform_driver_unregister(&e820_pmem_driver);
-}
+module_platform_driver(e820_pmem_driver);
 
 MODULE_ALIAS("platform:e820_pmem*");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Intel Corporation");
-module_init(e820_pmem_init);
-module_exit(e820_pmem_exit);
index fac7cabe8f563e8e0e08b97f79aeb4f86174f66f..dd615345699fddf38f9117344278bf9364afe547 100644 (file)
@@ -938,7 +938,7 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
                }
 
                for_each_dpa_resource(ndd, res)
-                       if (strncmp(res->name, "pmem", 3) == 0)
+                       if (strncmp(res->name, "pmem", 4) == 0)
                                count++;
                WARN_ON_ONCE(!count);
 
index abe5c6bc756c255193d803039973971368b9471d..6307088b375f2d899002f9fc9fae16c387357598 100644 (file)
@@ -1132,7 +1132,7 @@ static ssize_t size_show(struct device *dev,
        return sprintf(buf, "%llu\n", (unsigned long long)
                        nvdimm_namespace_capacity(to_ndns(dev)));
 }
-static DEVICE_ATTR(size, S_IRUGO, size_show, size_store);
+static DEVICE_ATTR(size, 0444, size_show, size_store);
 
 static u8 *namespace_to_uuid(struct device *dev)
 {
@@ -1456,7 +1456,7 @@ static umode_t namespace_visible(struct kobject *kobj,
 
        if (is_namespace_pmem(dev) || is_namespace_blk(dev)) {
                if (a == &dev_attr_size.attr)
-                       return S_IWUSR | S_IRUGO;
+                       return 0644;
 
                if (is_namespace_pmem(dev) && a == &dev_attr_sector_size.attr)
                        return 0;
@@ -1653,7 +1653,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
                u64 hw_start, hw_end, pmem_start, pmem_end;
                struct nd_label_ent *label_ent;
 
-               WARN_ON(!mutex_is_locked(&nd_mapping->lock));
+               lockdep_assert_held(&nd_mapping->lock);
                list_for_each_entry(label_ent, &nd_mapping->labels, list) {
                        nd_label = label_ent->label;
                        if (!nd_label)
@@ -1997,7 +1997,7 @@ struct device *create_namespace_blk(struct nd_region *nd_region,
        struct nd_mapping *nd_mapping = &nd_region->mapping[0];
        struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
        struct nd_namespace_blk *nsblk;
-       char *name[NSLABEL_NAME_LEN];
+       char name[NSLABEL_NAME_LEN];
        struct device *dev = NULL;
        struct resource *res;
 
index d3b2fca8deec20b930ca55e025c7f116b30f9199..35dd75057e1697f2e03de12c62cf3f6cabb69aec 100644 (file)
@@ -238,6 +238,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
                void *buf, size_t len);
 long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
                unsigned int len);
+void nvdimm_set_aliasing(struct device *dev);
 struct nd_btt *to_nd_btt(struct device *dev);
 
 struct nd_gen_sb {
@@ -377,10 +378,17 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start)
        if (!blk_queue_io_stat(disk->queue))
                return false;
 
-       __nd_iostat_start(bio, start);
+       *start = jiffies;
+       generic_start_io_acct(bio_data_dir(bio),
+                             bio_sectors(bio), &disk->part0);
        return true;
 }
-void nd_iostat_end(struct bio *bio, unsigned long start);
+static inline void nd_iostat_end(struct bio *bio, unsigned long start)
+{
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+
+       generic_end_io_acct(bio_data_dir(bio), &disk->part0, start);
+}
 static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
                unsigned int len)
 {
index cea8350fbc7ec2f2e617199fd2bc8b8cb1df2fbb..a2ac9e641aa9341f2fcca9fa8b968fd874e80a90 100644 (file)
@@ -108,7 +108,7 @@ static ssize_t align_show(struct device *dev,
 {
        struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
 
-       return sprintf(buf, "%lx\n", nd_pfn->align);
+       return sprintf(buf, "%ld\n", nd_pfn->align);
 }
 
 static ssize_t __align_store(struct nd_pfn *nd_pfn, const char *buf)
index 24618431a14bae7e891438b3601d017d1d34db4d..7282d7495bf1f0a1bf6685012dafb1d9cc60bfa4 100644 (file)
@@ -53,21 +53,24 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
        struct device *dev = to_dev(pmem);
        sector_t sector;
        long cleared;
+       int rc = 0;
 
        sector = (offset - pmem->data_offset) / 512;
-       cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
 
+       cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len);
+       if (cleared < len)
+               rc = -EIO;
        if (cleared > 0 && cleared / 512) {
-               dev_dbg(dev, "%s: %#llx clear %ld sector%s\n",
-                               __func__, (unsigned long long) sector,
-                               cleared / 512, cleared / 512 > 1 ? "s" : "");
-               badblocks_clear(&pmem->bb, sector, cleared / 512);
-       } else {
-               return -EIO;
+               cleared /= 512;
+               dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", __func__,
+                               (unsigned long long) sector, cleared,
+                               cleared > 1 ? "s" : "");
+               badblocks_clear(&pmem->bb, sector, cleared);
        }
 
        invalidate_pmem(pmem->virt_addr + offset, len);
-       return 0;
+
+       return rc;
 }
 
 static void write_pmem(void *pmem_addr, struct page *page,
@@ -270,7 +273,7 @@ static int pmem_attach_disk(struct device *dev,
                dev_warn(dev, "unable to guarantee persistence of writes\n");
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
-                               dev_name(dev))) {
+                               dev_name(&ndns->dev))) {
                dev_warn(dev, "could not reserve region %pR\n", res);
                return -EBUSY;
        }
index 6af5e629140cd3336d590c6ec24783ebd6e3d78d..7cd705f3247c341160a6b2ad7d1827c1604f34ce 100644 (file)
@@ -509,7 +509,7 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
 {
        struct nd_label_ent *label_ent, *e;
 
-       WARN_ON(!mutex_is_locked(&nd_mapping->lock));
+       lockdep_assert_held(&nd_mapping->lock);
        list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
                list_del(&label_ent->list);
                kfree(label_ent);
index 185376901d9c7412d434152e7fec31600da9f20b..5fe8be089b8b2dc51ced608e0790c7ce05b8dd18 100644 (file)
@@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP
          This is a driver for Lenovo IdeaPad netbooks contains drivers for
          rfkill switch, hotkey, fan control and backlight control.
 
+config SURFACE3_WMI
+       tristate "Surface 3 WMI Driver"
+       depends on ACPI_WMI
+       depends on DMI
+       depends on INPUT
+       depends on SPI
+       ---help---
+         Say Y here if you have a Surface 3.
+
+         To compile this driver as a module, choose M here: the module will
+         be called surface3-wmi.
+
 config THINKPAD_ACPI
        tristate "ThinkPad ACPI Laptop Extras"
        depends on ACPI
@@ -1005,12 +1017,27 @@ config INTEL_PMC_IPC
        The PMC is an ARC processor which defines IPC commands for communication
        with other entities in the CPU.
 
+config INTEL_BXTWC_PMIC_TMU
+       tristate "Intel BXT Whiskey Cove TMU Driver"
+       depends on REGMAP
+       depends on INTEL_SOC_PMIC && INTEL_PMC_IPC
+       ---help---
+         Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature.
+         This driver enables the alarm wakeup functionality in the TMU unit
+         of Whiskey Cove PMIC.
+
 config SURFACE_PRO3_BUTTON
        tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
        depends on ACPI && INPUT
        ---help---
          This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
 
+config SURFACE_3_BUTTON
+       tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet"
+       depends on ACPI && KEYBOARD_GPIO
+       ---help---
+         This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
+
 config INTEL_PUNIT_IPC
        tristate "Intel P-Unit IPC Driver"
        ---help---
@@ -1028,10 +1055,21 @@ config INTEL_TELEMETRY
          directly via debugfs files. Various tools may use
          this interface for SoC state monitoring.
 
+config MLX_PLATFORM
+       tristate "Mellanox Technologies platform support"
+       depends on X86_64
+       ---help---
+         This option enables system support for the Mellanox Technologies
+         platform. The Mellanox systems provide data center networking
+         solutions based on Virtual Protocol Interconnect (VPI) technology
+         enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE
+         connection.
+
+         If you have a Mellanox system, say Y or M here.
+
 config MLX_CPLD_PLATFORM
        tristate "Mellanox platform hotplug driver support"
        default n
-       depends on MLX_PLATFORM
        select HWMON
        select I2C
        ---help---
index 1f06b6339cf73cbb832518fe89cb95552a06e499..d4111f0f8a78fdbcc7a10ef5e236bdda1cdffc15 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP)        += panasonic-laptop.o
 obj-$(CONFIG_INTEL_MENLOW)     += intel_menlow.o
 obj-$(CONFIG_ACPI_WMI)         += wmi.o
 obj-$(CONFIG_MSI_WMI)          += msi-wmi.o
+obj-$(CONFIG_SURFACE3_WMI)     += surface3-wmi.o
 obj-$(CONFIG_TOPSTAR_LAPTOP)   += topstar-laptop.o
 
 # toshiba_acpi must link after wmi to ensure that wmi devices are found
@@ -66,9 +67,12 @@ obj-$(CONFIG_PVPANIC)           += pvpanic.o
 obj-$(CONFIG_ALIENWARE_WMI)    += alienware-wmi.o
 obj-$(CONFIG_INTEL_PMC_IPC)    += intel_pmc_ipc.o
 obj-$(CONFIG_SURFACE_PRO3_BUTTON)      += surfacepro3_button.o
+obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
 obj-$(CONFIG_INTEL_PUNIT_IPC)  += intel_punit_ipc.o
+obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU)     += intel_bxtwc_tmu.o
 obj-$(CONFIG_INTEL_TELEMETRY)  += intel_telemetry_core.o \
                                   intel_telemetry_pltdrv.o \
                                   intel_telemetry_debugfs.o
 obj-$(CONFIG_INTEL_PMC_CORE)    += intel_pmc_core.o
+obj-$(CONFIG_MLX_PLATFORM)     += mlx-platform.o
 obj-$(CONFIG_MLX_CPLD_PLATFORM)        += mlxcpld-hotplug.o
index a7614fc542b52aaaa4f58d91ea43bd9625e8de32..410741acb3c92dabe36417800f564a943c5d42ec 100644 (file)
@@ -870,6 +870,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
                },
        },
+       {
+               .ident = "Lenovo ideapad Y700-15ACZ",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
+               },
+       },
        {
                .ident = "Lenovo ideapad Y700-15ISK",
                .matches = {
diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c
new file mode 100644 (file)
index 0000000..e202abd
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This driver adds TMU (Time Management Unit) support for Intel BXT platform.
+ * It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove
+ * PMIC.
+ *
+ * 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/intel_soc_pmic.h>
+
+#define BXTWC_TMUIRQ           0x4fb6
+#define BXTWC_MIRQLVL1         0x4e0e
+#define BXTWC_MTMUIRQ_REG      0x4fb7
+#define BXTWC_MIRQLVL1_MTMU    BIT(1)
+#define BXTWC_TMU_WK_ALRM      BIT(1)
+#define BXTWC_TMU_SYS_ALRM     BIT(2)
+#define BXTWC_TMU_ALRM_MASK    (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
+#define BXTWC_TMU_ALRM_IRQ     (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM)
+
+struct wcove_tmu {
+       int irq;
+       struct device *dev;
+       struct regmap *regmap;
+};
+
+static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data)
+{
+       struct wcove_tmu *wctmu = data;
+       unsigned int tmu_irq;
+
+       /* Read TMU interrupt reg */
+       regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq);
+       if (tmu_irq & BXTWC_TMU_ALRM_IRQ) {
+               /* clear TMU irq */
+               regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+static int bxt_wcove_tmu_probe(struct platform_device *pdev)
+{
+       struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+       struct regmap_irq_chip_data *regmap_irq_chip;
+       struct wcove_tmu *wctmu;
+       int ret, virq, irq;
+
+       wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL);
+       if (!wctmu)
+               return -ENOMEM;
+
+       wctmu->dev = &pdev->dev;
+       wctmu->regmap = pmic->regmap;
+
+       irq = platform_get_irq(pdev, 0);
+
+       if (irq < 0) {
+               dev_err(&pdev->dev, "invalid irq %d\n", irq);
+               return irq;
+       }
+
+       regmap_irq_chip = pmic->irq_chip_data_tmu;
+       virq = regmap_irq_get_virq(regmap_irq_chip, irq);
+       if (virq < 0) {
+               dev_err(&pdev->dev,
+                       "failed to get virtual interrupt=%d\n", irq);
+               return virq;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, virq,
+                                       NULL, bxt_wcove_tmu_irq_handler,
+                                       IRQF_ONESHOT, "bxt_wcove_tmu", wctmu);
+       if (ret) {
+               dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n",
+                                                       ret, virq);
+               return ret;
+       }
+       wctmu->irq = virq;
+
+       /* Enable TMU interrupts */
+       regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1,
+                                 BXTWC_MIRQLVL1_MTMU, 0);
+
+       /* Unmask TMU second level Wake & System alarm */
+       regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG,
+                                 BXTWC_TMU_ALRM_MASK, 0);
+
+       platform_set_drvdata(pdev, wctmu);
+       return 0;
+}
+
+static int bxt_wcove_tmu_remove(struct platform_device *pdev)
+{
+       struct wcove_tmu *wctmu = platform_get_drvdata(pdev);
+       unsigned int val;
+
+       /* Mask TMU interrupts */
+       regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val);
+       regmap_write(wctmu->regmap, BXTWC_MIRQLVL1,
+                       val | BXTWC_MIRQLVL1_MTMU);
+       regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val);
+       regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG,
+                       val | BXTWC_TMU_ALRM_MASK);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bxtwc_tmu_suspend(struct device *dev)
+{
+       struct wcove_tmu *wctmu = dev_get_drvdata(dev);
+
+       enable_irq_wake(wctmu->irq);
+       return 0;
+}
+
+static int bxtwc_tmu_resume(struct device *dev)
+{
+       struct wcove_tmu *wctmu = dev_get_drvdata(dev);
+
+       disable_irq_wake(wctmu->irq);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume);
+
+static const struct platform_device_id bxt_wcove_tmu_id_table[] = {
+       { .name = "bxt_wcove_tmu" },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table);
+
+static struct platform_driver bxt_wcove_tmu_driver = {
+       .probe = bxt_wcove_tmu_probe,
+       .remove = bxt_wcove_tmu_remove,
+       .driver = {
+               .name = "bxt_wcove_tmu",
+               .pm     = &bxtwc_tmu_pm_ops,
+       },
+       .id_table = bxt_wcove_tmu_id_table,
+};
+
+module_platform_driver(bxt_wcove_tmu_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Nilesh Bacchewar <nilesh.bacchewar@intel.com>");
+MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver");
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
new file mode 100644 (file)
index 0000000..97b4c3a
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-mux-reg.h>
+#include <linux/platform_data/mlxcpld-hotplug.h>
+
+#define MLX_PLAT_DEVICE_NAME           "mlxplat"
+
+/* LPC bus IO offsets */
+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR         0x2000
+#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
+#define MLXPLAT_CPLD_LPC_IO_RANGE              0x100
+#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF           0xdb
+#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF           0xda
+#define MLXPLAT_CPLD_LPC_PIO_OFFSET            0x10000UL
+#define MLXPLAT_CPLD_LPC_REG1  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
+                                 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
+                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
+#define MLXPLAT_CPLD_LPC_REG2  ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
+                                 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
+                                 MLXPLAT_CPLD_LPC_PIO_OFFSET)
+
+/* Start channel numbers */
+#define MLXPLAT_CPLD_CH1                       2
+#define MLXPLAT_CPLD_CH2                       10
+
+/* Number of LPC attached MUX platform devices */
+#define MLXPLAT_CPLD_LPC_MUX_DEVS              2
+
+/* mlxplat_priv - platform private data
+ * @pdev_i2c - i2c controller platform device
+ * @pdev_mux - array of mux platform devices
+ */
+struct mlxplat_priv {
+       struct platform_device *pdev_i2c;
+       struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
+       struct platform_device *pdev_hotplug;
+};
+
+/* Regions for LPC I2C controller and LPC base register space */
+static const struct resource mlxplat_lpc_resources[] = {
+       [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
+                              MLXPLAT_CPLD_LPC_IO_RANGE,
+                              "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
+       [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
+                              MLXPLAT_CPLD_LPC_IO_RANGE,
+                              "mlxplat_cpld_lpc_regs",
+                              IORESOURCE_IO),
+};
+
+/* Platform default channels */
+static const int mlxplat_default_channels[][8] = {
+       {
+               MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
+               MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
+               5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
+       },
+       {
+               MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
+               MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
+               5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
+       },
+};
+
+/* Platform channels for MSN21xx system family */
+static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+/* Platform mux data */
+static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
+       {
+               .parent = 1,
+               .base_nr = MLXPLAT_CPLD_CH1,
+               .write_only = 1,
+               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
+               .reg_size = 1,
+               .idle_in_use = 1,
+       },
+       {
+               .parent = 1,
+               .base_nr = MLXPLAT_CPLD_CH2,
+               .write_only = 1,
+               .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
+               .reg_size = 1,
+               .idle_in_use = 1,
+       },
+
+};
+
+/* Platform hotplug devices */
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = {
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
+               .bus = 10,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
+               .bus = 10,
+       },
+};
+
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = {
+       {
+               .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
+               .bus = 10,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
+               .bus = 10,
+       },
+};
+
+static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = {
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 11,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 12,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 13,
+       },
+       {
+               .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
+               .bus = 14,
+       },
+};
+
+/* Platform hotplug default data */
+static
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = {
+       .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
+       .top_aggr_mask = 0x48,
+       .top_aggr_psu_mask = 0x08,
+       .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58),
+       .psu_mask = 0x03,
+       .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu),
+       .psu = mlxplat_mlxcpld_hotplug_psu,
+       .top_aggr_pwr_mask = 0x08,
+       .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
+       .pwr_mask = 0x03,
+       .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+       .pwr = mlxplat_mlxcpld_hotplug_pwr,
+       .top_aggr_fan_mask = 0x40,
+       .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88),
+       .fan_mask = 0x0f,
+       .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan),
+       .fan = mlxplat_mlxcpld_hotplug_fan,
+};
+
+/* Platform hotplug MSN21xx system family data */
+static
+struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = {
+       .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a),
+       .top_aggr_mask = 0x04,
+       .top_aggr_pwr_mask = 0x04,
+       .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64),
+       .pwr_mask = 0x03,
+       .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr),
+};
+
+static struct resource mlxplat_mlxcpld_hotplug_resources[] = {
+       [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"),
+};
+
+struct platform_device *mlxplat_dev;
+struct mlxcpld_hotplug_platform_data *mlxplat_hotplug;
+
+static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+               mlxplat_mux_data[i].values = mlxplat_default_channels[i];
+               mlxplat_mux_data[i].n_values =
+                               ARRAY_SIZE(mlxplat_default_channels[i]);
+       }
+       mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data;
+
+       return 1;
+};
+
+static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+               mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
+               mlxplat_mux_data[i].n_values =
+                               ARRAY_SIZE(mlxplat_msn21xx_channels);
+       }
+       mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data;
+
+       return 1;
+};
+
+static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_msn21xx_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
+               },
+       },
+       { }
+};
+
+static int __init mlxplat_init(void)
+{
+       struct mlxplat_priv *priv;
+       int i, err;
+
+       if (!dmi_check_system(mlxplat_dmi_table))
+               return -ENODEV;
+
+       mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
+                                       mlxplat_lpc_resources,
+                                       ARRAY_SIZE(mlxplat_lpc_resources));
+
+       if (IS_ERR(mlxplat_dev))
+               return PTR_ERR(mlxplat_dev);
+
+       priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
+                           GFP_KERNEL);
+       if (!priv) {
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+       platform_set_drvdata(mlxplat_dev, priv);
+
+       priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
+                                                        NULL, 0);
+       if (IS_ERR(priv->pdev_i2c)) {
+               err = PTR_ERR(priv->pdev_i2c);
+               goto fail_alloc;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+               priv->pdev_mux[i] = platform_device_register_resndata(
+                                               &mlxplat_dev->dev,
+                                               "i2c-mux-reg", i, NULL,
+                                               0, &mlxplat_mux_data[i],
+                                               sizeof(mlxplat_mux_data[i]));
+               if (IS_ERR(priv->pdev_mux[i])) {
+                       err = PTR_ERR(priv->pdev_mux[i]);
+                       goto fail_platform_mux_register;
+               }
+       }
+
+       priv->pdev_hotplug = platform_device_register_resndata(
+                               &mlxplat_dev->dev, "mlxcpld-hotplug", -1,
+                               mlxplat_mlxcpld_hotplug_resources,
+                               ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources),
+                               mlxplat_hotplug, sizeof(*mlxplat_hotplug));
+       if (IS_ERR(priv->pdev_hotplug)) {
+               err = PTR_ERR(priv->pdev_hotplug);
+               goto fail_platform_mux_register;
+       }
+
+       return 0;
+
+fail_platform_mux_register:
+       for (i--; i > 0 ; i--)
+               platform_device_unregister(priv->pdev_mux[i]);
+       platform_device_unregister(priv->pdev_i2c);
+fail_alloc:
+       platform_device_unregister(mlxplat_dev);
+
+       return err;
+}
+module_init(mlxplat_init);
+
+static void __exit mlxplat_exit(void)
+{
+       struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
+       int i;
+
+       platform_device_unregister(priv->pdev_hotplug);
+
+       for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
+               platform_device_unregister(priv->pdev_mux[i]);
+
+       platform_device_unregister(priv->pdev_i2c);
+       platform_device_unregister(mlxplat_dev);
+}
+module_exit(mlxplat_exit);
+
+MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
+MODULE_DESCRIPTION("Mellanox platform driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
+MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c
new file mode 100644 (file)
index 0000000..cbf4d83
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  Driver for the LID cover switch of the Surface 3
+ *
+ *  Copyright (c) 2016 Red Hat Inc.
+ */
+
+/*
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("Surface 3 platform driver");
+MODULE_LICENSE("GPL");
+
+#define ACPI_BUTTON_HID_LID            "PNP0C0D"
+#define SPI_CTL_OBJ_NAME               "SPI"
+#define SPI_TS_OBJ_NAME                        "NTRG"
+
+#define SURFACE3_LID_GUID "F7CC25EC-D20B-404C-8903-0ED4359C18AE"
+
+MODULE_ALIAS("wmi:" SURFACE3_LID_GUID);
+
+static const struct dmi_system_id surface3_dmi_table[] = {
+#if defined(CONFIG_X86)
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+               },
+       },
+#endif
+       { }
+};
+
+struct surface3_wmi {
+       struct acpi_device *touchscreen_adev;
+       struct acpi_device *pnp0c0d_adev;
+       struct acpi_hotplug_context hp;
+       struct input_dev *input;
+};
+
+static struct platform_device *s3_wmi_pdev;
+
+static struct surface3_wmi s3_wmi;
+
+static DEFINE_MUTEX(s3_wmi_lock);
+
+static int s3_wmi_query_block(const char *guid, int instance, int *ret)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+       union acpi_object *obj;
+       int error = 0;
+
+       mutex_lock(&s3_wmi_lock);
+       status = wmi_query_block(guid, instance, &output);
+
+       obj = output.pointer;
+
+       if (!obj || obj->type != ACPI_TYPE_INTEGER) {
+               if (obj) {
+                       pr_err("query block returned object type: %d - buffer length:%d\n",
+                              obj->type,
+                              obj->type == ACPI_TYPE_BUFFER ?
+                                               obj->buffer.length : 0);
+               }
+               error = -EINVAL;
+               goto out_free_unlock;
+       }
+       *ret = obj->integer.value;
+ out_free_unlock:
+       kfree(obj);
+       mutex_unlock(&s3_wmi_lock);
+       return error;
+}
+
+static inline int s3_wmi_query_lid(int *ret)
+{
+       return s3_wmi_query_block(SURFACE3_LID_GUID, 0, ret);
+}
+
+static int s3_wmi_send_lid_state(void)
+{
+       int ret, lid_sw;
+
+       ret = s3_wmi_query_lid(&lid_sw);
+       if (ret)
+               return ret;
+
+       input_report_switch(s3_wmi.input, SW_LID, lid_sw);
+       input_sync(s3_wmi.input);
+
+       return 0;
+}
+
+static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value)
+{
+       return s3_wmi_send_lid_state();
+}
+
+static acpi_status s3_wmi_attach_spi_device(acpi_handle handle,
+                                           u32 level,
+                                           void *data,
+                                           void **return_value)
+{
+       struct acpi_device *adev, **ts_adev;
+
+       if (acpi_bus_get_device(handle, &adev))
+               return AE_OK;
+
+       ts_adev = data;
+
+       if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME,
+           strlen(SPI_TS_OBJ_NAME)))
+               return AE_OK;
+
+       if (*ts_adev) {
+               pr_err("duplicate entry %s\n", SPI_TS_OBJ_NAME);
+               return AE_OK;
+       }
+
+       *ts_adev = adev;
+
+       return AE_OK;
+}
+
+static int s3_wmi_check_platform_device(struct device *dev, void *data)
+{
+       struct acpi_device *adev, *ts_adev;
+       acpi_handle handle;
+       acpi_status status;
+
+       /* ignore non ACPI devices */
+       handle = ACPI_HANDLE(dev);
+       if (!handle || acpi_bus_get_device(handle, &adev))
+               return 0;
+
+       /* check for LID ACPI switch */
+       if (!strcmp(ACPI_BUTTON_HID_LID, acpi_device_hid(adev))) {
+               s3_wmi.pnp0c0d_adev = adev;
+               return 0;
+       }
+
+       /* ignore non SPI controllers */
+       if (strncmp(acpi_device_bid(adev), SPI_CTL_OBJ_NAME,
+           strlen(SPI_CTL_OBJ_NAME)))
+               return 0;
+
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                                    s3_wmi_attach_spi_device, NULL,
+                                    &ts_adev, NULL);
+       if (ACPI_FAILURE(status))
+               dev_warn(dev, "failed to enumerate SPI slaves\n");
+
+       if (!ts_adev)
+               return 0;
+
+       s3_wmi.touchscreen_adev = ts_adev;
+
+       return 0;
+}
+
+static int s3_wmi_create_and_register_input(struct platform_device *pdev)
+{
+       struct input_dev *input;
+       int error;
+
+       input = devm_input_allocate_device(&pdev->dev);
+       if (!input)
+               return -ENOMEM;
+
+       input->name = "Lid Switch";
+       input->phys = "button/input0";
+       input->id.bustype = BUS_HOST;
+       input->id.product = 0x0005;
+
+       input_set_capability(input, EV_SW, SW_LID);
+
+       error = input_register_device(input);
+       if (error)
+               goto out_err;
+
+       s3_wmi.input = input;
+
+       return 0;
+ out_err:
+       input_free_device(s3_wmi.input);
+       return error;
+}
+
+static int __init s3_wmi_probe(struct platform_device *pdev)
+{
+       int error;
+
+       if (!dmi_check_system(surface3_dmi_table))
+               return -ENODEV;
+
+       memset(&s3_wmi, 0, sizeof(s3_wmi));
+
+       bus_for_each_dev(&platform_bus_type, NULL, NULL,
+                        s3_wmi_check_platform_device);
+
+       if (!s3_wmi.touchscreen_adev)
+               return -ENODEV;
+
+       acpi_bus_trim(s3_wmi.pnp0c0d_adev);
+
+       error = s3_wmi_create_and_register_input(pdev);
+       if (error)
+               goto restore_acpi_lid;
+
+       acpi_initialize_hp_context(s3_wmi.touchscreen_adev, &s3_wmi.hp,
+                                  s3_wmi_hp_notify, NULL);
+
+       s3_wmi_send_lid_state();
+
+       return 0;
+
+ restore_acpi_lid:
+       acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+       return error;
+}
+
+static int s3_wmi_remove(struct platform_device *device)
+{
+       /* remove the hotplug context from the acpi device */
+       s3_wmi.touchscreen_adev->hp = NULL;
+
+       /* reinstall the actual PNPC0C0D LID default handle */
+       acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3_wmi_resume(struct device *dev)
+{
+       s3_wmi_send_lid_state();
+       return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume);
+
+static struct platform_driver s3_wmi_driver = {
+       .driver = {
+               .name = "surface3-wmi",
+               .pm = &s3_wmi_pm,
+       },
+       .remove = s3_wmi_remove,
+};
+
+static int __init s3_wmi_init(void)
+{
+       int error;
+
+       s3_wmi_pdev = platform_device_alloc("surface3-wmi", -1);
+       if (!s3_wmi_pdev)
+               return -ENOMEM;
+
+       error = platform_device_add(s3_wmi_pdev);
+       if (error)
+               goto err_device_put;
+
+       error = platform_driver_probe(&s3_wmi_driver, s3_wmi_probe);
+       if (error)
+               goto err_device_del;
+
+       pr_info("Surface 3 WMI Extras loaded\n");
+       return 0;
+
+ err_device_del:
+       platform_device_del(s3_wmi_pdev);
+ err_device_put:
+       platform_device_put(s3_wmi_pdev);
+       return error;
+}
+
+static void __exit s3_wmi_exit(void)
+{
+       platform_device_unregister(s3_wmi_pdev);
+       platform_driver_unregister(&s3_wmi_driver);
+}
+
+module_init(s3_wmi_init);
+module_exit(s3_wmi_exit);
diff --git a/drivers/platform/x86/surface3_button.c b/drivers/platform/x86/surface3_button.c
new file mode 100644 (file)
index 0000000..8bfd7f6
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Supports for the button array on the Surface tablets.
+ *
+ * (C) Copyright 2016 Red Hat, Inc
+ *
+ * Based on soc_button_array.c:
+ *
+ * {C} Copyright 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.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+
+
+#define SURFACE_BUTTON_OBJ_NAME                "TEV2"
+#define MAX_NBUTTONS                   4
+
+/*
+ * Some of the buttons like volume up/down are auto repeat, while others
+ * are not. To support both, we register two platform devices, and put
+ * buttons into them based on whether the key should be auto repeat.
+ */
+#define BUTTON_TYPES                   2
+
+/*
+ * Power button, Home button, Volume buttons support is supposed to
+ * be covered by drivers/input/misc/soc_button_array.c, which is implemented
+ * according to "Windows ACPI Design Guide for SoC Platforms".
+ * However surface 3 seems not to obey the specs, instead it uses
+ * device TEV2(MSHW0028) for declaring the GPIOs. The gpios are also slightly
+ * different in which the Home button is active high.
+ * Compared to surfacepro3_button.c which also handles MSHW0028, the Surface 3
+ * is a reduce platform and thus uses GPIOs, not ACPI events.
+ * We choose an I2C driver here because we need to access the resources
+ * declared under the device node, while surfacepro3_button.c only needs
+ * the ACPI companion node.
+ */
+static const struct acpi_device_id surface3_acpi_match[] = {
+       { "MSHW0028", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, surface3_acpi_match);
+
+struct surface3_button_info {
+       const char *name;
+       int acpi_index;
+       unsigned int event_type;
+       unsigned int event_code;
+       bool autorepeat;
+       bool wakeup;
+       bool active_low;
+};
+
+struct surface3_button_data {
+       struct platform_device *children[BUTTON_TYPES];
+};
+
+/*
+ * Get the Nth GPIO number from the ACPI object.
+ */
+static int surface3_button_lookup_gpio(struct device *dev, int acpi_index)
+{
+       struct gpio_desc *desc;
+       int gpio;
+
+       desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       gpio = desc_to_gpio(desc);
+
+       gpiod_put(desc);
+
+       return gpio;
+}
+
+static struct platform_device *
+surface3_button_device_create(struct i2c_client *client,
+                             const struct surface3_button_info *button_info,
+                             bool autorepeat)
+{
+       const struct surface3_button_info *info;
+       struct platform_device *pd;
+       struct gpio_keys_button *gpio_keys;
+       struct gpio_keys_platform_data *gpio_keys_pdata;
+       int n_buttons = 0;
+       int gpio;
+       int error;
+
+       gpio_keys_pdata = devm_kzalloc(&client->dev,
+                                      sizeof(*gpio_keys_pdata) +
+                                      sizeof(*gpio_keys) * MAX_NBUTTONS,
+                                      GFP_KERNEL);
+       if (!gpio_keys_pdata)
+               return ERR_PTR(-ENOMEM);
+
+       gpio_keys = (void *)(gpio_keys_pdata + 1);
+
+       for (info = button_info; info->name; info++) {
+               if (info->autorepeat != autorepeat)
+                       continue;
+
+               gpio = surface3_button_lookup_gpio(&client->dev,
+                                                  info->acpi_index);
+               if (!gpio_is_valid(gpio))
+                       continue;
+
+               gpio_keys[n_buttons].type = info->event_type;
+               gpio_keys[n_buttons].code = info->event_code;
+               gpio_keys[n_buttons].gpio = gpio;
+               gpio_keys[n_buttons].active_low = info->active_low;
+               gpio_keys[n_buttons].desc = info->name;
+               gpio_keys[n_buttons].wakeup = info->wakeup;
+               n_buttons++;
+       }
+
+       if (n_buttons == 0) {
+               error = -ENODEV;
+               goto err_free_mem;
+       }
+
+       gpio_keys_pdata->buttons = gpio_keys;
+       gpio_keys_pdata->nbuttons = n_buttons;
+       gpio_keys_pdata->rep = autorepeat;
+
+       pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
+       if (!pd) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       error = platform_device_add_data(pd, gpio_keys_pdata,
+                                        sizeof(*gpio_keys_pdata));
+       if (error)
+               goto err_free_pdev;
+
+       error = platform_device_add(pd);
+       if (error)
+               goto err_free_pdev;
+
+       return pd;
+
+err_free_pdev:
+       platform_device_put(pd);
+err_free_mem:
+       devm_kfree(&client->dev, gpio_keys_pdata);
+       return ERR_PTR(error);
+}
+
+static int surface3_button_remove(struct i2c_client *client)
+{
+       struct surface3_button_data *priv = i2c_get_clientdata(client);
+
+       int i;
+
+       for (i = 0; i < BUTTON_TYPES; i++)
+               if (priv->children[i])
+                       platform_device_unregister(priv->children[i]);
+
+       return 0;
+}
+
+static struct surface3_button_info surface3_button_surface3[] = {
+       { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+       { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
+       { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+       { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+       { }
+};
+
+static int surface3_button_probe(struct i2c_client *client,
+                                const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct surface3_button_data *priv;
+       struct platform_device *pd;
+       int i;
+       int error;
+
+       if (strncmp(acpi_device_bid(ACPI_COMPANION(&client->dev)),
+                   SURFACE_BUTTON_OBJ_NAME,
+                   strlen(SURFACE_BUTTON_OBJ_NAME)))
+               return -ENODEV;
+
+       if (gpiod_count(dev, KBUILD_MODNAME) <= 0) {
+               dev_dbg(dev, "no GPIO attached, ignoring...\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, priv);
+
+       for (i = 0; i < BUTTON_TYPES; i++) {
+               pd = surface3_button_device_create(client,
+                                                  surface3_button_surface3,
+                                                  i == 0);
+               if (IS_ERR(pd)) {
+                       error = PTR_ERR(pd);
+                       if (error != -ENODEV) {
+                               surface3_button_remove(client);
+                               return error;
+                       }
+                       continue;
+               }
+
+               priv->children[i] = pd;
+       }
+
+       if (!priv->children[0] && !priv->children[1])
+               return -ENODEV;
+
+       return 0;
+}
+
+static const struct i2c_device_id surface3_id[] = {
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, surface3_id);
+
+static struct i2c_driver surface3_driver = {
+       .probe = surface3_button_probe,
+       .remove = surface3_button_remove,
+       .id_table = surface3_id,
+       .driver = {
+               .name = "surface3",
+               .acpi_match_table = ACPI_PTR(surface3_acpi_match),
+       },
+};
+module_i2c_driver(surface3_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("surface3 button array driver");
+MODULE_LICENSE("GPL v2");
index eb0f5b13841a505ea4157e949cf179d71d26175e..9aafbb03482d735fcc55bdfab3df83249900a024 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
                           DCDC5, DCDC6, LDO1, LS3 };
 
-#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
-                          _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
+#define TPS65218_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
+                          _em, _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
        {                                                       \
                .name                   = _name,                \
+               .of_match               = _of,                  \
                .id                     = _id,                  \
                .ops                    = &_ops,                \
                .n_voltages             = _n,                   \
@@ -54,14 +56,6 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
                .bypass_mask    = _sm,                          \
        }                                                       \
 
-#define TPS65218_INFO(_id, _nm, _min, _max)    \
-       [_id] = {                                       \
-               .id             = _id,                  \
-               .name           = _nm,                  \
-               .min_uV         = _min,                 \
-               .max_uV         = _max,                 \
-       }
-
 static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = {
        REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000),
        REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000),
@@ -77,36 +71,6 @@ static const struct regulator_linear_range dcdc4_ranges[] = {
        REGULATOR_LINEAR_RANGE(1600000, 0x10, 0x34, 50000),
 };
 
-static struct tps_info tps65218_pmic_regs[] = {
-       TPS65218_INFO(DCDC1, "DCDC1", 850000, 1675000),
-       TPS65218_INFO(DCDC2, "DCDC2", 850000, 1675000),
-       TPS65218_INFO(DCDC3, "DCDC3", 900000, 3400000),
-       TPS65218_INFO(DCDC4, "DCDC4", 1175000, 3400000),
-       TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
-       TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
-       TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
-       TPS65218_INFO(LS3, "LS3", -1, -1),
-};
-
-#define TPS65218_OF_MATCH(comp, label) \
-       { \
-               .compatible = comp, \
-               .data = &label, \
-       }
-
-static const struct of_device_id tps65218_of_match[] = {
-       TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]),
-       TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]),
-       TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]),
-       TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
-       { }
-};
-MODULE_DEVICE_TABLE(of, tps65218_of_match);
-
 static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev,
                                         unsigned selector)
 {
@@ -188,7 +152,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
        if (rid == TPS65218_DCDC_3 && tps->rev == TPS65218_REV_2_1)
                return 0;
 
-       if (!tps->info[rid]->strobe) {
+       if (!tps->strobes[rid]) {
                if (rid == TPS65218_DCDC_3)
                        tps->info[rid]->strobe = 3;
                else
@@ -197,8 +161,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
 
        return tps65218_set_bits(tps, dev->desc->bypass_reg,
                                 dev->desc->bypass_mask,
-                                tps->info[rid]->strobe,
-                                TPS65218_PROTECT_L1);
+                                tps->strobes[rid], TPS65218_PROTECT_L1);
 }
 
 /* Operations permitted on DCDC1, DCDC2 */
@@ -272,7 +235,7 @@ static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
        unsigned int index;
        struct tps65218 *tps = rdev_get_drvdata(dev);
 
-       retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
+       retval = regmap_read(tps->regmap, dev->desc->csel_reg, &index);
        if (retval < 0)
                return retval;
 
@@ -300,104 +263,104 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
 };
 
 static const struct regulator_desc regulators[] = {
-       TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
-                          tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
+       TPS65218_REGULATOR("DCDC1", "regulator-dcdc1", TPS65218_DCDC_1,
+                          REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC1,
                           TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
                           2, 4000, 0, TPS65218_REG_SEQ3,
                           TPS65218_SEQ3_DC1_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
-                          tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
+       TPS65218_REGULATOR("DCDC2", "regulator-dcdc2", TPS65218_DCDC_2,
+                          REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64,
+                          TPS65218_REG_CONTROL_DCDC2,
                           TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
                           2, 4000, 0, TPS65218_REG_SEQ3,
                           TPS65218_SEQ3_DC2_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
-                          tps65218_ldo1_dcdc34_ops, 64,
+       TPS65218_REGULATOR("DCDC3", "regulator-dcdc3", TPS65218_DCDC_3,
+                          REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64,
                           TPS65218_REG_CONTROL_DCDC3,
                           TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
                           0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
-                          tps65218_ldo1_dcdc34_ops, 53,
+       TPS65218_REGULATOR("DCDC4", "regulator-dcdc4", TPS65218_DCDC_4,
+                          REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53,
                           TPS65218_REG_CONTROL_DCDC4,
                           TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
                           TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
                           0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
-                          tps65218_dcdc56_pmic_ops, 1, -1, -1,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
-                          NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
+       TPS65218_REGULATOR("DCDC5", "regulator-dcdc5", TPS65218_DCDC_5,
+                          REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1,
+                          -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0,
+                          0, NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
                           TPS65218_SEQ5_DC5_SEQ_MASK),
-       TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
-                          tps65218_dcdc56_pmic_ops, 1, -1, -1,
-                          TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
-                          NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
+       TPS65218_REGULATOR("DCDC6", "regulator-dcdc6", TPS65218_DCDC_6,
+                          REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1,
+                          -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0,
+                          0, NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
                           TPS65218_SEQ5_DC6_SEQ_MASK),
-       TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
-                          tps65218_ldo1_dcdc34_ops, 64,
+       TPS65218_REGULATOR("LDO1", "regulator-ldo1", TPS65218_LDO_1,
+                          REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64,
                           TPS65218_REG_CONTROL_LDO1,
                           TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
                           TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
                           2, 0, 0, TPS65218_REG_SEQ6,
                           TPS65218_SEQ6_LDO1_SEQ_MASK),
-       TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
-                          tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
-                          TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
-                          TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0),
+       TPS65218_REGULATOR("LS3", "regulator-ls3", TPS65218_LS_3,
+                          REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0,
+                          TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN,
+                          TPS65218_REG_CONFIG2, TPS65218_CONFIG2_LS3ILIM_MASK,
+                          NULL, 0, 0, 0, 0, 0),
 };
 
 static int tps65218_regulator_probe(struct platform_device *pdev)
 {
        struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
-       struct regulator_init_data *init_data;
-       const struct tps_info   *template;
        struct regulator_dev *rdev;
-       const struct of_device_id       *match;
        struct regulator_config config = { };
-       int id, ret;
+       int i, ret;
        unsigned int val;
 
-       match = of_match_device(tps65218_of_match, &pdev->dev);
-       if (!match)
-               return -ENODEV;
-
-       template = match->data;
-       id = template->id;
-       init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
-                                              &regulators[id]);
-
-       platform_set_drvdata(pdev, tps);
-
-       tps->info[id] = &tps65218_pmic_regs[id];
        config.dev = &pdev->dev;
-       config.init_data = init_data;
+       config.dev->of_node = tps->dev->of_node;
        config.driver_data = tps;
        config.regmap = tps->regmap;
-       config.of_node = pdev->dev.of_node;
 
-       rdev = devm_regulator_register(&pdev->dev, &regulators[id], &config);
-       if (IS_ERR(rdev)) {
-               dev_err(tps->dev, "failed to register %s regulator\n",
-                       pdev->name);
-               return PTR_ERR(rdev);
-       }
+       /* Allocate memory for strobes */
+       tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) *
+                                   TPS65218_NUM_REGULATOR, GFP_KERNEL);
 
-       ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val);
-       if (ret)
-               return ret;
+       for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+               rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(tps->dev, "failed to register %s regulator\n",
+                               pdev->name);
+                       return PTR_ERR(rdev);
+               }
 
-       tps->info[id]->strobe = val & regulators[id].bypass_mask;
+               ret = regmap_read(tps->regmap, regulators[i].bypass_reg, &val);
+               if (ret)
+                       return ret;
+
+               tps->strobes[i] = val & regulators[i].bypass_mask;
+       }
 
        return 0;
 }
 
+static const struct platform_device_id tps65218_regulator_id_table[] = {
+       { "tps65218-regulator", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65218_regulator_id_table);
+
 static struct platform_driver tps65218_regulator_driver = {
        .driver = {
                .name = "tps65218-pmic",
-               .of_match_table = tps65218_of_match,
        },
        .probe = tps65218_regulator_probe,
+       .id_table = tps65218_regulator_id_table,
 };
 
 module_platform_driver(tps65218_regulator_driver);
index e859d148aba9ecdbcecc47e745209b94ed83dd67..c93c5a8fba32925584dbc28c60610786328d09ff 100644 (file)
@@ -303,7 +303,7 @@ config RTC_DRV_MAX6900
 
 config RTC_DRV_MAX8907
        tristate "Maxim MAX8907"
-       depends on MFD_MAX8907
+       depends on MFD_MAX8907 || COMPILE_TEST
        help
          If you say yes here you will get support for the
          RTC of Maxim MAX8907 PMIC.
@@ -343,7 +343,7 @@ config RTC_DRV_MAX8997
 
 config RTC_DRV_MAX77686
        tristate "Maxim MAX77686"
-       depends on MFD_MAX77686 || MFD_MAX77620
+       depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
        help
          If you say yes here you will get support for the
          RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
@@ -481,6 +481,7 @@ config RTC_DRV_TWL92330
 config RTC_DRV_TWL4030
        tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
        depends on TWL4030_CORE
+       depends on OF
        help
          If you say yes here you get support for the RTC on the
          TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
@@ -602,7 +603,8 @@ config RTC_DRV_RV8803
 
 config RTC_DRV_S5M
        tristate "Samsung S2M/S5M series"
-       depends on MFD_SEC_CORE
+       depends on MFD_SEC_CORE || COMPILE_TEST
+       select REGMAP_IRQ
        help
          If you say yes here you will get support for the
          RTC of Samsung S2MPS14 and S5M PMIC series.
@@ -820,8 +822,8 @@ config RTC_DRV_RV3029_HWMON
 
 comment "Platform RTC drivers"
 
-# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
-# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+# this 'CMOS' RTC driver is arch dependent because it requires
+# <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
 # global rtc_lock ... it's not yet just another platform_device.
 
 config RTC_DRV_CMOS
@@ -1549,14 +1551,11 @@ config RTC_DRV_MPC5121
          will be called rtc-mpc5121.
 
 config RTC_DRV_JZ4740
-       tristate "Ingenic JZ4740 SoC"
-       depends on MACH_JZ4740 || COMPILE_TEST
+       bool "Ingenic JZ4740 SoC"
+       depends on MACH_INGENIC || COMPILE_TEST
        help
-         If you say yes here you get support for the Ingenic JZ4740 SoC RTC
-         controller.
-
-         This driver can also be buillt as a module. If so, the module
-         will be called rtc-jz4740.
+         If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
+         controllers.
 
 config RTC_DRV_LPC24XX
        tristate "NXP RTC for LPC178x/18xx/408x/43xx"
@@ -1567,7 +1566,7 @@ config RTC_DRV_LPC24XX
          NXP LPC178x/18xx/408x/43xx devices.
 
          If you have one of the devices above enable this driver to use
-         the hardware RTC. This driver can also be buillt as a module. If
+         the hardware RTC. This driver can also be built as a module. If
          so, the module will be called rtc-lpc24xx.
 
 config RTC_DRV_LPC32XX
@@ -1576,7 +1575,7 @@ config RTC_DRV_LPC32XX
        help
          This enables support for the NXP RTC in the LPC32XX
 
-         This driver can also be buillt as a module. If so, the module
+         This driver can also be built as a module. If so, the module
          will be called rtc-lpc32xx.
 
 config RTC_DRV_PM8XXX
@@ -1706,6 +1705,17 @@ config RTC_DRV_PIC32
           This driver can also be built as a module. If so, the module
           will be called rtc-pic32
 
+config RTC_DRV_R7301
+       tristate "EPSON TOYOCOM RTC-7301SF/DG"
+       select REGMAP_MMIO
+       depends on OF && HAS_IOMEM
+       help
+          If you say yes here you get support for the EPSON TOYOCOM
+          RTC-7301SF/DG chips.
+
+          This driver can also be built as a module. If so, the module
+          will be called rtc-r7301.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
index 1ac694a330c8dadc0cbe78a4f6cd8d7359de2ecc..f13ab1c5c222c269e711786e74f5a99a258150a5 100644 (file)
@@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_PM8XXX)        += rtc-pm8xxx.o
 obj-$(CONFIG_RTC_DRV_PS3)      += rtc-ps3.o
 obj-$(CONFIG_RTC_DRV_PUV3)     += rtc-puv3.o
 obj-$(CONFIG_RTC_DRV_PXA)      += rtc-pxa.o
+obj-$(CONFIG_RTC_DRV_R7301)    += rtc-r7301.o
 obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RC5T583)  += rtc-rc5t583.o
 obj-$(CONFIG_RTC_DRV_RK808)    += rtc-rk808.o
index 38aa8e1906c262dc9f367d94230422fb5a2be82c..f4a96dbdabf21ec4bdf8017e524ea42b9b0ce5c7 100644 (file)
@@ -332,14 +332,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
        cmos_checkintr(cmos, rtc_control);
 }
 
+static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct cmos_rtc *cmos = dev_get_drvdata(dev);
+       struct rtc_time now;
+
+       cmos_read_time(dev, &now);
+
+       if (!cmos->day_alrm) {
+               time64_t t_max_date;
+               time64_t t_alrm;
+
+               t_max_date = rtc_tm_to_time64(&now);
+               t_max_date += 24 * 60 * 60 - 1;
+               t_alrm = rtc_tm_to_time64(&t->time);
+               if (t_alrm > t_max_date) {
+                       dev_err(dev,
+                               "Alarms can be up to one day in the future\n");
+                       return -EINVAL;
+               }
+       } else if (!cmos->mon_alrm) {
+               struct rtc_time max_date = now;
+               time64_t t_max_date;
+               time64_t t_alrm;
+               int max_mday;
+
+               if (max_date.tm_mon == 11) {
+                       max_date.tm_mon = 0;
+                       max_date.tm_year += 1;
+               } else {
+                       max_date.tm_mon += 1;
+               }
+               max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
+               if (max_date.tm_mday > max_mday)
+                       max_date.tm_mday = max_mday;
+
+               t_max_date = rtc_tm_to_time64(&max_date);
+               t_max_date -= 1;
+               t_alrm = rtc_tm_to_time64(&t->time);
+               if (t_alrm > t_max_date) {
+                       dev_err(dev,
+                               "Alarms can be up to one month in the future\n");
+                       return -EINVAL;
+               }
+       } else {
+               struct rtc_time max_date = now;
+               time64_t t_max_date;
+               time64_t t_alrm;
+               int max_mday;
+
+               max_date.tm_year += 1;
+               max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
+               if (max_date.tm_mday > max_mday)
+                       max_date.tm_mday = max_mday;
+
+               t_max_date = rtc_tm_to_time64(&max_date);
+               t_max_date -= 1;
+               t_alrm = rtc_tm_to_time64(&t->time);
+               if (t_alrm > t_max_date) {
+                       dev_err(dev,
+                               "Alarms can be up to one year in the future\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
        unsigned char mon, mday, hrs, min, sec, rtc_control;
+       int ret;
 
        if (!is_valid_irq(cmos->irq))
                return -EIO;
 
+       ret = cmos_validate_alarm(dev, t);
+       if (ret < 0)
+               return ret;
+
        mon = t->time.tm_mon + 1;
        mday = t->time.tm_mday;
        hrs = t->time.tm_hour;
@@ -707,9 +779,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 
        spin_unlock_irq(&rtc_lock);
 
-       /* FIXME:
-        * <asm-generic/rtc.h> doesn't know 12-hour mode either.
-        */
        if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
                dev_warn(dev, "only 24-hr supported\n");
                retval = -ENXIO;
index 4e31036ee2596dec93accd26f627c5b95591ae9f..4ad97be480430babc3321075f2739114eaad8f04 100644 (file)
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/acpi.h>
 #include <linux/bcd.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
@@ -191,6 +192,26 @@ static const struct i2c_device_id ds1307_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ds1307_acpi_ids[] = {
+       { .id = "DS1307", .driver_data = ds_1307 },
+       { .id = "DS1337", .driver_data = ds_1337 },
+       { .id = "DS1338", .driver_data = ds_1338 },
+       { .id = "DS1339", .driver_data = ds_1339 },
+       { .id = "DS1388", .driver_data = ds_1388 },
+       { .id = "DS1340", .driver_data = ds_1340 },
+       { .id = "DS3231", .driver_data = ds_3231 },
+       { .id = "M41T00", .driver_data = m41t00 },
+       { .id = "MCP7940X", .driver_data = mcp794xx },
+       { .id = "MCP7941X", .driver_data = mcp794xx },
+       { .id = "PT7C4338", .driver_data = ds_1307 },
+       { .id = "RX8025", .driver_data = rx_8025 },
+       { .id = "ISL12057", .driver_data = ds_1337 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
+#endif
+
 /*----------------------------------------------------------------------*/
 
 #define BLOCK_DATA_MAX_TRIES 10
@@ -874,17 +895,17 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client,
        return setup;
 }
 
-static void ds1307_trickle_of_init(struct i2c_client *client,
-                                  struct chip_desc *chip)
+static void ds1307_trickle_init(struct i2c_client *client,
+                               struct chip_desc *chip)
 {
        uint32_t ohms = 0;
        bool diode = true;
 
        if (!chip->do_trickle_setup)
                goto out;
-       if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms))
+       if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms))
                goto out;
-       if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable"))
+       if (device_property_read_bool(&client->dev, "trickle-diode-disable"))
                diode = false;
        chip->trickle_charger_setup = chip->do_trickle_setup(client,
                                                             ohms, diode);
@@ -1268,7 +1289,7 @@ static int ds1307_probe(struct i2c_client *client,
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
        int                     tmp, wday;
-       struct chip_desc        *chip = &chips[id->driver_data];
+       struct chip_desc        *chip;
        struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        bool                    ds1307_can_wakeup_device = false;
@@ -1297,11 +1318,23 @@ static int ds1307_probe(struct i2c_client *client,
        i2c_set_clientdata(client, ds1307);
 
        ds1307->client  = client;
-       ds1307->type    = id->driver_data;
+       if (id) {
+               chip = &chips[id->driver_data];
+               ds1307->type = id->driver_data;
+       } else {
+               const struct acpi_device_id *acpi_id;
+
+               acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
+                                           &client->dev);
+               if (!acpi_id)
+                       return -ENODEV;
+               chip = &chips[acpi_id->driver_data];
+               ds1307->type = acpi_id->driver_data;
+       }
 
-       if (!pdata && client->dev.of_node)
-               ds1307_trickle_of_init(client, chip);
-       else if (pdata && pdata->trickle_charger_setup)
+       if (!pdata)
+               ds1307_trickle_init(client, chip);
+       else if (pdata->trickle_charger_setup)
                chip->trickle_charger_setup = pdata->trickle_charger_setup;
 
        if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
@@ -1678,6 +1711,7 @@ static int ds1307_remove(struct i2c_client *client)
 static struct i2c_driver ds1307_driver = {
        .driver = {
                .name   = "rtc-ds1307",
+               .acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
        },
        .probe          = ds1307_probe,
        .remove         = ds1307_remove,
index 3b3049c8c9e04ddb8ebfb3c391eba41b320286f3..52429f0a57cc2125e428aa88be917a4268f44b35 100644 (file)
@@ -89,10 +89,8 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
        int ret;
        int i;
 
-       if (nbytes > 4) {
-               WARN_ON(1);
+       if (WARN_ON(nbytes > 4))
                return -EINVAL;
-       }
 
        ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);
 
index 8d8049bdfaf613a83336fd22ed326ddfe9717716..67b56b80dc7097049dbf20f0ea8d0e908a231b5f 100644 (file)
@@ -67,7 +67,7 @@
 #define DSR_ETAD  (1 << 21)      /* External tamper A detected */
 #define DSR_EBD   (1 << 20)      /* External boot detected */
 #define DSR_SAD   (1 << 19)      /* SCC alarm detected */
-#define DSR_TTD   (1 << 18)      /* Temperatur tamper detected */
+#define DSR_TTD   (1 << 18)      /* Temperature tamper detected */
 #define DSR_CTD   (1 << 17)      /* Clock tamper detected */
 #define DSR_VTD   (1 << 16)      /* Voltage tamper detected */
 #define DSR_WBF   (1 << 10)      /* Write Busy Flag (synchronous) */
index 5e14651b71a89a2327a2f1fe175cc56156d6a880..72918c1ba0928d4fc78d921db621c489fafb9701 100644 (file)
  *
  */
 
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/reboot.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #define JZ_REG_RTC_SEC_ALARM   0x08
 #define JZ_REG_RTC_REGULATOR   0x0C
 #define JZ_REG_RTC_HIBERNATE   0x20
+#define JZ_REG_RTC_WAKEUP_FILTER       0x24
+#define JZ_REG_RTC_RESET_COUNTER       0x28
 #define JZ_REG_RTC_SCRATCHPAD  0x34
 
+/* The following are present on the jz4780 */
+#define JZ_REG_RTC_WENR        0x3C
+#define JZ_RTC_WENR_WEN        BIT(31)
+
 #define JZ_RTC_CTRL_WRDY       BIT(7)
 #define JZ_RTC_CTRL_1HZ                BIT(6)
 #define JZ_RTC_CTRL_1HZ_IRQ    BIT(5)
 #define JZ_RTC_CTRL_AE         BIT(2)
 #define JZ_RTC_CTRL_ENABLE     BIT(0)
 
+/* Magic value to enable writes on jz4780 */
+#define JZ_RTC_WENR_MAGIC      0xA55A
+
+#define JZ_RTC_WAKEUP_FILTER_MASK      0x0000FFE0
+#define JZ_RTC_RESET_COUNTER_MASK      0x00000FE0
+
+enum jz4740_rtc_type {
+       ID_JZ4740,
+       ID_JZ4780,
+};
+
 struct jz4740_rtc {
        void __iomem *base;
+       enum jz4740_rtc_type type;
 
        struct rtc_device *rtc;
+       struct clk *clk;
 
        int irq;
 
        spinlock_t lock;
+
+       unsigned int min_wakeup_pin_assert_time;
+       unsigned int reset_pin_assert_time;
 };
 
+static struct device *dev_for_power_off;
+
 static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
 {
        return readl(rtc->base + reg);
@@ -64,11 +90,33 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
        return timeout ? 0 : -EIO;
 }
 
+static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
+{
+       uint32_t ctrl;
+       int ret, timeout = 1000;
+
+       ret = jz4740_rtc_wait_write_ready(rtc);
+       if (ret != 0)
+               return ret;
+
+       writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
+
+       do {
+               ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
+       } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
+
+       return timeout ? 0 : -EIO;
+}
+
 static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
        uint32_t val)
 {
-       int ret;
-       ret = jz4740_rtc_wait_write_ready(rtc);
+       int ret = 0;
+
+       if (rtc->type >= ID_JZ4780)
+               ret = jz4780_rtc_enable_write(rtc);
+       if (ret == 0)
+               ret = jz4740_rtc_wait_write_ready(rtc);
        if (ret == 0)
                writel(val, rtc->base + reg);
 
@@ -203,12 +251,57 @@ static irqreturn_t jz4740_rtc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-void jz4740_rtc_poweroff(struct device *dev)
+static void jz4740_rtc_poweroff(struct device *dev)
 {
        struct jz4740_rtc *rtc = dev_get_drvdata(dev);
        jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1);
 }
-EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
+
+static void jz4740_rtc_power_off(void)
+{
+       struct jz4740_rtc *rtc = dev_get_drvdata(dev_for_power_off);
+       unsigned long rtc_rate;
+       unsigned long wakeup_filter_ticks;
+       unsigned long reset_counter_ticks;
+
+       clk_prepare_enable(rtc->clk);
+
+       rtc_rate = clk_get_rate(rtc->clk);
+
+       /*
+        * Set minimum wakeup pin assertion time: 100 ms.
+        * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
+        */
+       wakeup_filter_ticks =
+               (rtc->min_wakeup_pin_assert_time * rtc_rate) / 1000;
+       if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
+               wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
+       else
+               wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
+       jz4740_rtc_reg_write(rtc,
+                            JZ_REG_RTC_WAKEUP_FILTER, wakeup_filter_ticks);
+
+       /*
+        * Set reset pin low-level assertion time after wakeup: 60 ms.
+        * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
+        */
+       reset_counter_ticks = (rtc->reset_pin_assert_time * rtc_rate) / 1000;
+       if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
+               reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
+       else
+               reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
+       jz4740_rtc_reg_write(rtc,
+                            JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks);
+
+       jz4740_rtc_poweroff(dev_for_power_off);
+       machine_halt();
+}
+
+static const struct of_device_id jz4740_rtc_of_match[] = {
+       { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
+       { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
+       {},
+};
 
 static int jz4740_rtc_probe(struct platform_device *pdev)
 {
@@ -216,11 +309,20 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        struct jz4740_rtc *rtc;
        uint32_t scratchpad;
        struct resource *mem;
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       const struct of_device_id *of_id = of_match_device(
+                       jz4740_rtc_of_match, &pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
+       if (of_id)
+               rtc->type = (enum jz4740_rtc_type)of_id->data;
+       else
+               rtc->type = id->driver_data;
+
        rtc->irq = platform_get_irq(pdev, 0);
        if (rtc->irq < 0) {
                dev_err(&pdev->dev, "Failed to get platform irq\n");
@@ -232,6 +334,12 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(rtc->base))
                return PTR_ERR(rtc->base);
 
+       rtc->clk = devm_clk_get(&pdev->dev, "rtc");
+       if (IS_ERR(rtc->clk)) {
+               dev_err(&pdev->dev, "Failed to get RTC clock\n");
+               return PTR_ERR(rtc->clk);
+       }
+
        spin_lock_init(&rtc->lock);
 
        platform_set_drvdata(pdev, rtc);
@@ -263,6 +371,27 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
                }
        }
 
+       if (np && of_device_is_system_power_controller(np)) {
+               if (!pm_power_off) {
+                       /* Default: 60ms */
+                       rtc->reset_pin_assert_time = 60;
+                       of_property_read_u32(np, "reset-pin-assert-time-ms",
+                                            &rtc->reset_pin_assert_time);
+
+                       /* Default: 100ms */
+                       rtc->min_wakeup_pin_assert_time = 100;
+                       of_property_read_u32(np,
+                                            "min-wakeup-pin-assert-time-ms",
+                                            &rtc->min_wakeup_pin_assert_time);
+
+                       dev_for_power_off = &pdev->dev;
+                       pm_power_off = jz4740_rtc_power_off;
+               } else {
+                       dev_warn(&pdev->dev,
+                                "Poweroff handler already present!\n");
+               }
+       }
+
        return 0;
 }
 
@@ -295,17 +424,20 @@ static const struct dev_pm_ops jz4740_pm_ops = {
 #define JZ4740_RTC_PM_OPS NULL
 #endif  /* CONFIG_PM */
 
+static const struct platform_device_id jz4740_rtc_ids[] = {
+       { "jz4740-rtc", ID_JZ4740 },
+       { "jz4780-rtc", ID_JZ4780 },
+       {}
+};
+
 static struct platform_driver jz4740_rtc_driver = {
        .probe   = jz4740_rtc_probe,
        .driver  = {
                .name  = "jz4740-rtc",
                .pm    = JZ4740_RTC_PM_OPS,
+               .of_match_table = of_match_ptr(jz4740_rtc_of_match),
        },
+       .id_table = jz4740_rtc_ids,
 };
 
-module_platform_driver(jz4740_rtc_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
-MODULE_ALIAS("platform:jz4740-rtc");
+builtin_platform_driver(jz4740_rtc_driver);
index e6bfb9c42a10b08948910345e34f1b3b83057e82..1ae7da5cfc608f6c4bcb3764b00683e2a54b7919 100644 (file)
@@ -11,7 +11,7 @@
  * published by the Free Software Foundation.
 */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/rtc.h>
 
 static const unsigned char rtc_days_in_month[] = {
@@ -148,5 +148,3 @@ struct rtc_time rtc_ktime_to_tm(ktime_t kt)
        return ret;
 }
 EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
-
-MODULE_LICENSE("GPL");
index 4021fd04cb0ac847c955c4de79e283a97b73ff17..ce75e421ba001fce02c7f7afce57c310af012001 100644 (file)
@@ -12,7 +12,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * */
+ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -21,6 +21,8 @@
 #include <linux/spi/spi.h>
 #include <linux/rtc.h>
 #include <linux/of.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
 
 /* MCP795 Instructions, see datasheet table 3-1 */
 #define MCP795_EEREAD  0x03
@@ -29,7 +31,7 @@
 #define MCP795_EEWREN  0x06
 #define MCP795_SRREAD  0x05
 #define MCP795_SRWRITE 0x01
-#define MCP795_READ            0x13
+#define MCP795_READ    0x13
 #define MCP795_WRITE   0x12
 #define MCP795_UNLOCK  0x14
 #define MCP795_IDWRITE 0x32
 #define MCP795_CLRWDT  0x44
 #define MCP795_CLRRAM  0x54
 
-#define MCP795_ST_BIT  0x80
-#define MCP795_24_BIT  0x40
+/* MCP795 RTCC registers, see datasheet table 4-1 */
+#define MCP795_REG_SECONDS     0x01
+#define MCP795_REG_DAY         0x04
+#define MCP795_REG_MONTH       0x06
+#define MCP795_REG_CONTROL     0x08
+
+#define MCP795_ST_BIT          BIT(7)
+#define MCP795_24_BIT          BIT(6)
+#define MCP795_LP_BIT          BIT(5)
+#define MCP795_EXTOSC_BIT      BIT(3)
+#define MCP795_OSCON_BIT       BIT(5)
 
 static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count)
 {
@@ -93,30 +104,97 @@ static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state)
        return ret;
 }
 
+static int mcp795_stop_oscillator(struct device *dev, bool *extosc)
+{
+       int retries = 5;
+       int ret;
+       u8 data;
+
+       ret = mcp795_rtcc_set_bits(dev, MCP795_REG_SECONDS, MCP795_ST_BIT, 0);
+       if (ret)
+               return ret;
+       ret = mcp795_rtcc_read(dev, MCP795_REG_CONTROL, &data, 1);
+       if (ret)
+               return ret;
+       *extosc = !!(data & MCP795_EXTOSC_BIT);
+       ret = mcp795_rtcc_set_bits(
+                               dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, 0);
+       if (ret)
+               return ret;
+       /* wait for the OSCON bit to clear */
+       do {
+               usleep_range(700, 800);
+               ret = mcp795_rtcc_read(dev, MCP795_REG_DAY, &data, 1);
+               if (ret)
+                       break;
+               if (!(data & MCP795_OSCON_BIT))
+                       break;
+
+       } while (--retries);
+
+       return !retries ? -EIO : ret;
+}
+
+static int mcp795_start_oscillator(struct device *dev, bool *extosc)
+{
+       if (extosc) {
+               u8 data = *extosc ? MCP795_EXTOSC_BIT : 0;
+               int ret;
+
+               ret = mcp795_rtcc_set_bits(
+                       dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, data);
+               if (ret)
+                       return ret;
+       }
+       return mcp795_rtcc_set_bits(
+                       dev, MCP795_REG_SECONDS, MCP795_ST_BIT, MCP795_ST_BIT);
+}
+
 static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
 {
        int ret;
        u8 data[7];
+       bool extosc;
+
+       /* Stop RTC and store current value of EXTOSC bit */
+       ret = mcp795_stop_oscillator(dev, &extosc);
+       if (ret)
+               return ret;
 
        /* Read first, so we can leave config bits untouched */
-       ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
+       ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
 
        if (ret)
                return ret;
 
-       data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10);
-       data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10);
-       data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10);
-       data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10);
-       data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10);
+       data[0] = (data[0] & 0x80) | bin2bcd(tim->tm_sec);
+       data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min);
+       data[2] = bin2bcd(tim->tm_hour);
+       data[4] = bin2bcd(tim->tm_mday);
+       data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon + 1);
 
        if (tim->tm_year > 100)
                tim->tm_year -= 100;
 
-       data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10);
+       data[6] = bin2bcd(tim->tm_year);
+
+       /* Always write the date and month using a separate Write command.
+        * This is a workaround for a know silicon issue that some combinations
+        * of date and month values may result in the date being reset to 1.
+        */
+       ret = mcp795_rtcc_write(dev, MCP795_REG_SECONDS, data, 5);
+       if (ret)
+               return ret;
 
-       ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data));
+       ret = mcp795_rtcc_write(dev, MCP795_REG_MONTH, &data[5], 2);
+       if (ret)
+               return ret;
 
+       /* Start back RTC and restore previous value of EXTOSC bit.
+        * There is no need to clear EXTOSC bit when the previous value was 0
+        * because it was already cleared when stopping the RTC oscillator.
+        */
+       ret = mcp795_start_oscillator(dev, extosc ? &extosc : NULL);
        if (ret)
                return ret;
 
@@ -132,17 +210,17 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim)
        int ret;
        u8 data[7];
 
-       ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
+       ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
 
        if (ret)
                return ret;
 
-       tim->tm_sec             = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f);
-       tim->tm_min             = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f);
-       tim->tm_hour    = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f);
-       tim->tm_mday    = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f);
-       tim->tm_mon             = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f);
-       tim->tm_year    = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */
+       tim->tm_sec     = bcd2bin(data[0] & 0x7F);
+       tim->tm_min     = bcd2bin(data[1] & 0x7F);
+       tim->tm_hour    = bcd2bin(data[2] & 0x3F);
+       tim->tm_mday    = bcd2bin(data[4] & 0x3F);
+       tim->tm_mon     = bcd2bin(data[5] & 0x1F) - 1;
+       tim->tm_year    = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */
 
        dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
                                tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
@@ -169,13 +247,13 @@ static int mcp795_probe(struct spi_device *spi)
                return ret;
        }
 
-       /* Start the oscillator */
-       mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT);
+       /* Start the oscillator but don't set the value of EXTOSC bit */
+       mcp795_start_oscillator(&spi->dev, NULL);
        /* Clear the 12 hour mode flag*/
        mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0);
 
        rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795",
-                                                               &mcp795_rtc_ops, THIS_MODULE);
+                                       &mcp795_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
 
index efb0a08ac1175182a07ef9d63a49184a20698bd4..a06dff994c8316c0062b39d3704055a1305584a8 100644 (file)
@@ -191,12 +191,19 @@ static int pcf85063_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        struct rtc_device *rtc;
+       int err;
 
        dev_dbg(&client->dev, "%s\n", __func__);
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
+       err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
+       if (err < 0) {
+               dev_err(&client->dev, "RTC chip is not present\n");
+               return err;
+       }
+
        rtc = devm_rtc_device_register(&client->dev,
                                       pcf85063_driver.driver.name,
                                       &pcf85063_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c
new file mode 100644 (file)
index 0000000..28d5408
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * EPSON TOYOCOM RTC-7301SF/DG Driver
+ *
+ * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
+ *
+ * Based on rtc-rp5c01.c
+ *
+ * Datasheet: http://www5.epsondevice.com/en/products/parallel/rtc7301sf.html
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "rtc-r7301"
+
+#define RTC7301_1_SEC          0x0     /* Bank 0 and Band 1 */
+#define RTC7301_10_SEC         0x1     /* Bank 0 and Band 1 */
+#define RTC7301_AE             BIT(3)
+#define RTC7301_1_MIN          0x2     /* Bank 0 and Band 1 */
+#define RTC7301_10_MIN         0x3     /* Bank 0 and Band 1 */
+#define RTC7301_1_HOUR         0x4     /* Bank 0 and Band 1 */
+#define RTC7301_10_HOUR                0x5     /* Bank 0 and Band 1 */
+#define RTC7301_DAY_OF_WEEK    0x6     /* Bank 0 and Band 1 */
+#define RTC7301_1_DAY          0x7     /* Bank 0 and Band 1 */
+#define RTC7301_10_DAY         0x8     /* Bank 0 and Band 1 */
+#define RTC7301_1_MONTH                0x9     /* Bank 0 */
+#define RTC7301_10_MONTH       0xa     /* Bank 0 */
+#define RTC7301_1_YEAR         0xb     /* Bank 0 */
+#define RTC7301_10_YEAR                0xc     /* Bank 0 */
+#define RTC7301_100_YEAR       0xd     /* Bank 0 */
+#define RTC7301_1000_YEAR      0xe     /* Bank 0 */
+#define RTC7301_ALARM_CONTROL  0xe     /* Bank 1 */
+#define RTC7301_ALARM_CONTROL_AIE      BIT(0)
+#define RTC7301_ALARM_CONTROL_AF       BIT(1)
+#define RTC7301_TIMER_CONTROL  0xe     /* Bank 2 */
+#define RTC7301_TIMER_CONTROL_TIE      BIT(0)
+#define RTC7301_TIMER_CONTROL_TF       BIT(1)
+#define RTC7301_CONTROL                0xf     /* All banks */
+#define RTC7301_CONTROL_BUSY           BIT(0)
+#define RTC7301_CONTROL_STOP           BIT(1)
+#define RTC7301_CONTROL_BANK_SEL_0     BIT(2)
+#define RTC7301_CONTROL_BANK_SEL_1     BIT(3)
+
+struct rtc7301_priv {
+       struct regmap *regmap;
+       int irq;
+       spinlock_t lock;
+       u8 bank;
+};
+
+static const struct regmap_config rtc7301_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 8,
+       .reg_stride = 4,
+};
+
+static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
+{
+       int reg_stride = regmap_get_reg_stride(priv->regmap);
+       unsigned int val;
+
+       regmap_read(priv->regmap, reg_stride * reg, &val);
+
+       return val & 0xf;
+}
+
+static void rtc7301_write(struct rtc7301_priv *priv, u8 val, unsigned int reg)
+{
+       int reg_stride = regmap_get_reg_stride(priv->regmap);
+
+       regmap_write(priv->regmap, reg_stride * reg, val);
+}
+
+static void rtc7301_update_bits(struct rtc7301_priv *priv, unsigned int reg,
+                               u8 mask, u8 val)
+{
+       int reg_stride = regmap_get_reg_stride(priv->regmap);
+
+       regmap_update_bits(priv->regmap, reg_stride * reg, mask, val);
+}
+
+static int rtc7301_wait_while_busy(struct rtc7301_priv *priv)
+{
+       int retries = 100;
+
+       while (retries-- > 0) {
+               u8 val;
+
+               val = rtc7301_read(priv, RTC7301_CONTROL);
+               if (!(val & RTC7301_CONTROL_BUSY))
+                       return 0;
+
+               usleep_range(200, 300);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static void rtc7301_stop(struct rtc7301_priv *priv)
+{
+       rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP,
+                           RTC7301_CONTROL_STOP);
+}
+
+static void rtc7301_start(struct rtc7301_priv *priv)
+{
+       rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, 0);
+}
+
+static void rtc7301_select_bank(struct rtc7301_priv *priv, u8 bank)
+{
+       u8 val = 0;
+
+       if (bank == priv->bank)
+               return;
+
+       if (bank & BIT(0))
+               val |= RTC7301_CONTROL_BANK_SEL_0;
+       if (bank & BIT(1))
+               val |= RTC7301_CONTROL_BANK_SEL_1;
+
+       rtc7301_update_bits(priv, RTC7301_CONTROL,
+                           RTC7301_CONTROL_BANK_SEL_0 |
+                           RTC7301_CONTROL_BANK_SEL_1, val);
+
+       priv->bank = bank;
+}
+
+static void rtc7301_get_time(struct rtc7301_priv *priv, struct rtc_time *tm,
+                            bool alarm)
+{
+       int year;
+
+       tm->tm_sec = rtc7301_read(priv, RTC7301_1_SEC);
+       tm->tm_sec += (rtc7301_read(priv, RTC7301_10_SEC) & ~RTC7301_AE) * 10;
+       tm->tm_min = rtc7301_read(priv, RTC7301_1_MIN);
+       tm->tm_min += (rtc7301_read(priv, RTC7301_10_MIN) & ~RTC7301_AE) * 10;
+       tm->tm_hour = rtc7301_read(priv, RTC7301_1_HOUR);
+       tm->tm_hour += (rtc7301_read(priv, RTC7301_10_HOUR) & ~RTC7301_AE) * 10;
+       tm->tm_mday = rtc7301_read(priv, RTC7301_1_DAY);
+       tm->tm_mday += (rtc7301_read(priv, RTC7301_10_DAY) & ~RTC7301_AE) * 10;
+
+       if (alarm) {
+               tm->tm_wday = -1;
+               tm->tm_mon = -1;
+               tm->tm_year = -1;
+               tm->tm_yday = -1;
+               tm->tm_isdst = -1;
+               return;
+       }
+
+       tm->tm_wday = (rtc7301_read(priv, RTC7301_DAY_OF_WEEK) & ~RTC7301_AE);
+       tm->tm_mon = rtc7301_read(priv, RTC7301_10_MONTH) * 10 +
+                    rtc7301_read(priv, RTC7301_1_MONTH) - 1;
+       year = rtc7301_read(priv, RTC7301_1000_YEAR) * 1000 +
+              rtc7301_read(priv, RTC7301_100_YEAR) * 100 +
+              rtc7301_read(priv, RTC7301_10_YEAR) * 10 +
+              rtc7301_read(priv, RTC7301_1_YEAR);
+
+       tm->tm_year = year - 1900;
+}
+
+static void rtc7301_write_time(struct rtc7301_priv *priv, struct rtc_time *tm,
+                              bool alarm)
+{
+       int year;
+
+       rtc7301_write(priv, tm->tm_sec % 10, RTC7301_1_SEC);
+       rtc7301_write(priv, tm->tm_sec / 10, RTC7301_10_SEC);
+
+       rtc7301_write(priv, tm->tm_min % 10, RTC7301_1_MIN);
+       rtc7301_write(priv, tm->tm_min / 10, RTC7301_10_MIN);
+
+       rtc7301_write(priv, tm->tm_hour % 10, RTC7301_1_HOUR);
+       rtc7301_write(priv, tm->tm_hour / 10, RTC7301_10_HOUR);
+
+       rtc7301_write(priv, tm->tm_mday % 10, RTC7301_1_DAY);
+       rtc7301_write(priv, tm->tm_mday / 10, RTC7301_10_DAY);
+
+       /* Don't care for alarm register */
+       rtc7301_write(priv, alarm ? RTC7301_AE : tm->tm_wday,
+                     RTC7301_DAY_OF_WEEK);
+
+       if (alarm)
+               return;
+
+       rtc7301_write(priv, (tm->tm_mon + 1) % 10, RTC7301_1_MONTH);
+       rtc7301_write(priv, (tm->tm_mon + 1) / 10, RTC7301_10_MONTH);
+
+       year = tm->tm_year + 1900;
+
+       rtc7301_write(priv, year % 10, RTC7301_1_YEAR);
+       rtc7301_write(priv, (year / 10) % 10, RTC7301_10_YEAR);
+       rtc7301_write(priv, (year / 100) % 10, RTC7301_100_YEAR);
+       rtc7301_write(priv, year / 1000, RTC7301_1000_YEAR);
+}
+
+static void rtc7301_alarm_irq(struct rtc7301_priv *priv, unsigned int enabled)
+{
+       rtc7301_update_bits(priv, RTC7301_ALARM_CONTROL,
+                           RTC7301_ALARM_CONTROL_AF |
+                           RTC7301_ALARM_CONTROL_AIE,
+                           enabled ? RTC7301_ALARM_CONTROL_AIE : 0);
+}
+
+static int rtc7301_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 0);
+
+       err = rtc7301_wait_while_busy(priv);
+       if (!err)
+               rtc7301_get_time(priv, tm, false);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return err ? err : rtc_valid_tm(tm);
+}
+
+static int rtc7301_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_stop(priv);
+       usleep_range(200, 300);
+       rtc7301_select_bank(priv, 0);
+       rtc7301_write_time(priv, tm, false);
+       rtc7301_start(priv);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int rtc7301_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       u8 alrm_ctrl;
+
+       if (priv->irq <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+       rtc7301_get_time(priv, &alarm->time, true);
+
+       alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
+
+       alarm->enabled = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AIE);
+       alarm->pending = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AF);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int rtc7301_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       if (priv->irq <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+       rtc7301_write_time(priv, &alarm->time, true);
+       rtc7301_alarm_irq(priv, alarm->enabled);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int rtc7301_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       if (priv->irq <= 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+       rtc7301_alarm_irq(priv, enabled);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static const struct rtc_class_ops rtc7301_rtc_ops = {
+       .read_time      = rtc7301_read_time,
+       .set_time       = rtc7301_set_time,
+       .read_alarm     = rtc7301_read_alarm,
+       .set_alarm      = rtc7301_set_alarm,
+       .alarm_irq_enable = rtc7301_alarm_irq_enable,
+};
+
+static irqreturn_t rtc7301_irq_handler(int irq, void *dev_id)
+{
+       struct rtc_device *rtc = dev_id;
+       struct rtc7301_priv *priv = dev_get_drvdata(rtc->dev.parent);
+       unsigned long flags;
+       irqreturn_t ret = IRQ_NONE;
+       u8 alrm_ctrl;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 1);
+
+       alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
+       if (alrm_ctrl & RTC7301_ALARM_CONTROL_AF) {
+               ret = IRQ_HANDLED;
+               rtc7301_alarm_irq(priv, false);
+               rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
+}
+
+static void rtc7301_init(struct rtc7301_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rtc7301_select_bank(priv, 2);
+       rtc7301_write(priv, 0, RTC7301_TIMER_CONTROL);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int __init rtc7301_rtc_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       void __iomem *regs;
+       struct rtc7301_priv *priv;
+       struct rtc_device *rtc;
+       int ret;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       regs = devm_ioremap_resource(&dev->dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
+                                            &rtc7301_regmap_config);
+       if (IS_ERR(priv->regmap))
+               return PTR_ERR(priv->regmap);
+
+       priv->irq = platform_get_irq(dev, 0);
+
+       spin_lock_init(&priv->lock);
+       priv->bank = -1;
+
+       rtc7301_init(priv);
+
+       platform_set_drvdata(dev, priv);
+
+       rtc = devm_rtc_device_register(&dev->dev, DRV_NAME, &rtc7301_rtc_ops,
+                                      THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       if (priv->irq > 0) {
+               ret = devm_request_irq(&dev->dev, priv->irq,
+                                      rtc7301_irq_handler, IRQF_SHARED,
+                                      dev_name(&dev->dev), rtc);
+               if (ret) {
+                       priv->irq = 0;
+                       dev_err(&dev->dev, "unable to request IRQ\n");
+               } else {
+                       device_set_wakeup_capable(&dev->dev, true);
+               }
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int rtc7301_suspend(struct device *dev)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(priv->irq);
+
+       return 0;
+}
+
+static int rtc7301_resume(struct device *dev)
+{
+       struct rtc7301_priv *priv = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(priv->irq);
+
+       return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(rtc7301_pm_ops, rtc7301_suspend, rtc7301_resume);
+
+static const struct of_device_id rtc7301_dt_match[] = {
+       { .compatible = "epson,rtc7301sf" },
+       { .compatible = "epson,rtc7301dg" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, rtc7301_dt_match);
+
+static struct platform_driver rtc7301_rtc_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = rtc7301_dt_match,
+               .pm = &rtc7301_pm_ops,
+       },
+};
+
+module_platform_driver_probe(rtc7301_rtc_driver, rtc7301_rtc_probe);
+
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EPSON TOYOCOM RTC-7301SF/DG Driver");
+MODULE_ALIAS("platform:rtc-r7301");
index 83a057a0306072ff5efc4beebbcc6f5727b30307..7fc36973fa330e4845b84f688800d6903556de38 100644 (file)
@@ -1,20 +1,18 @@
 /* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Author: David S. Miller
+ * License: GPL
  *
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 
 #include <asm/oplib.h>
 
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("Starfire RTC driver");
-MODULE_LICENSE("GPL");
-
 static u32 starfire_get_time(void)
 {
        static char obp_gettod[32];
@@ -57,4 +55,4 @@ static struct platform_driver starfire_rtc_driver = {
        },
 };
 
-module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
+builtin_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
index 7c696c12f28f8cf36bdbc281ffcf3d52a68b133d..11bc562eba5dfb7d9aa749ff9e951397b9d6c7a8 100644 (file)
@@ -1,4 +1,7 @@
 /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Author: David S. Miller
+ * License: GPL
  *
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
@@ -6,7 +9,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/rtc.h>
@@ -98,8 +100,4 @@ static struct platform_driver sun4v_rtc_driver = {
        },
 };
 
-module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
-
-MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
-MODULE_DESCRIPTION("SUN4V RTC driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
index 176720b7b9e5083195b3bd789dbf5a8a622cd6c8..c18c39212ce680929b72c07e0ebe6305bb2675d8 100644 (file)
 
 #include <linux/i2c/twl.h>
 
+enum twl_class {
+       TWL_4030 = 0,
+       TWL_6030,
+};
 
 /*
  * RTC block register offsets (use TWL_MODULE_RTC)
@@ -136,16 +140,30 @@ static const u8 twl6030_rtc_reg_map[] = {
 #define ALL_TIME_REGS          6
 
 /*----------------------------------------------------------------------*/
-static u8  *rtc_reg_map;
+struct twl_rtc {
+       struct device *dev;
+       struct rtc_device *rtc;
+       u8 *reg_map;
+       /*
+        * Cache the value for timer/alarm interrupts register; this is
+        * only changed by callers holding rtc ops lock (or resume).
+        */
+       unsigned char rtc_irq_bits;
+       bool wake_enabled;
+#ifdef CONFIG_PM_SLEEP
+       unsigned char irqstat;
+#endif
+       enum twl_class class;
+};
 
 /*
  * Supports 1 byte read from TWL RTC register.
  */
-static int twl_rtc_read_u8(u8 *data, u8 reg)
+static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg)
 {
        int ret;
 
-       ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+       ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
        if (ret < 0)
                pr_err("Could not read TWL register %X - error %d\n", reg, ret);
        return ret;
@@ -154,40 +172,34 @@ static int twl_rtc_read_u8(u8 *data, u8 reg)
 /*
  * Supports 1 byte write to TWL RTC registers.
  */
-static int twl_rtc_write_u8(u8 data, u8 reg)
+static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg)
 {
        int ret;
 
-       ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
+       ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
        if (ret < 0)
                pr_err("Could not write TWL register %X - error %d\n",
                       reg, ret);
        return ret;
 }
 
-/*
- * Cache the value for timer/alarm interrupts register; this is
- * only changed by callers holding rtc ops lock (or resume).
- */
-static unsigned char rtc_irq_bits;
-
 /*
  * Enable 1/second update and/or alarm interrupts.
  */
-static int set_rtc_irq_bit(unsigned char bit)
+static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
 {
        unsigned char val;
        int ret;
 
        /* if the bit is set, return from here */
-       if (rtc_irq_bits & bit)
+       if (twl_rtc->rtc_irq_bits & bit)
                return 0;
 
-       val = rtc_irq_bits | bit;
+       val = twl_rtc->rtc_irq_bits | bit;
        val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
-       ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
        if (ret == 0)
-               rtc_irq_bits = val;
+               twl_rtc->rtc_irq_bits = val;
 
        return ret;
 }
@@ -195,19 +207,19 @@ static int set_rtc_irq_bit(unsigned char bit)
 /*
  * Disable update and/or alarm interrupts.
  */
-static int mask_rtc_irq_bit(unsigned char bit)
+static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
 {
        unsigned char val;
        int ret;
 
        /* if the bit is clear, return from here */
-       if (!(rtc_irq_bits & bit))
+       if (!(twl_rtc->rtc_irq_bits & bit))
                return 0;
 
-       val = rtc_irq_bits & ~bit;
-       ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       val = twl_rtc->rtc_irq_bits & ~bit;
+       ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
        if (ret == 0)
-               rtc_irq_bits = val;
+               twl_rtc->rtc_irq_bits = val;
 
        return ret;
 }
@@ -215,21 +227,23 @@ static int mask_rtc_irq_bit(unsigned char bit)
 static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
 {
        struct platform_device *pdev = to_platform_device(dev);
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        int irq = platform_get_irq(pdev, 0);
-       static bool twl_rtc_wake_enabled;
        int ret;
 
        if (enabled) {
-               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-               if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) {
+               ret = set_rtc_irq_bit(twl_rtc,
+                                     BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+               if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) {
                        enable_irq_wake(irq);
-                       twl_rtc_wake_enabled = true;
+                       twl_rtc->wake_enabled = true;
                }
        } else {
-               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-               if (twl_rtc_wake_enabled) {
+               ret = mask_rtc_irq_bit(twl_rtc,
+                                      BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+               if (twl_rtc->wake_enabled) {
                        disable_irq_wake(irq);
-                       twl_rtc_wake_enabled = false;
+                       twl_rtc->wake_enabled = false;
                }
        }
 
@@ -247,21 +261,23 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
  */
 static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        unsigned char rtc_data[ALL_TIME_REGS];
        int ret;
        u8 save_control;
        u8 rtc_control;
 
-       ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
        if (ret < 0) {
                dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret);
                return ret;
        }
        /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
-       if (twl_class_is_6030()) {
+       if (twl_rtc->class == TWL_6030) {
                if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) {
                        save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M;
-                       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+                       ret = twl_rtc_write_u8(twl_rtc, save_control,
+                                              REG_RTC_CTRL_REG);
                        if (ret < 0) {
                                dev_err(dev, "%s clr GET_TIME, error %d\n",
                                        __func__, ret);
@@ -274,17 +290,17 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
        rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M;
 
        /* for twl6030/32 enable read access to static shadowed registers */
-       if (twl_class_is_6030())
+       if (twl_rtc->class == TWL_6030)
                rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT;
 
-       ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG);
        if (ret < 0) {
                dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret);
                return ret;
        }
 
        ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
-                       (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+                       (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
 
        if (ret < 0) {
                dev_err(dev, "%s: reading data, error %d\n", __func__, ret);
@@ -292,8 +308,8 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
        }
 
        /* for twl6030 restore original state of rtc control register */
-       if (twl_class_is_6030()) {
-               ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       if (twl_rtc->class == TWL_6030) {
+               ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
                if (ret < 0) {
                        dev_err(dev, "%s: restore CTRL_REG, error %d\n",
                                __func__, ret);
@@ -313,6 +329,7 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        unsigned char save_control;
        unsigned char rtc_data[ALL_TIME_REGS];
        int ret;
@@ -325,18 +342,18 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
        rtc_data[5] = bin2bcd(tm->tm_year - 100);
 
        /* Stop RTC while updating the TC registers */
-       ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
        if (ret < 0)
                goto out;
 
        save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
-       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
        if (ret < 0)
                goto out;
 
        /* update all the time registers in one shot */
        ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
-               (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
+               (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
        if (ret < 0) {
                dev_err(dev, "rtc_set_time error %d\n", ret);
                goto out;
@@ -344,7 +361,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
        /* Start back RTC */
        save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
-       ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
 
 out:
        return ret;
@@ -355,11 +372,12 @@ out:
  */
 static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
        unsigned char rtc_data[ALL_TIME_REGS];
        int ret;
 
        ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
-                       (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+                       twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
        if (ret < 0) {
                dev_err(dev, "rtc_read_alarm error %d\n", ret);
                return ret;
@@ -374,7 +392,7 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
        alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
 
        /* report cached alarm enable state */
-       if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+       if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
                alm->enabled = 1;
 
        return ret;
@@ -382,6 +400,8 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
 static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
        unsigned char alarm_data[ALL_TIME_REGS];
        int ret;
 
@@ -398,7 +418,7 @@ static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
        /* update all the alarm registers in one shot */
        ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
-               (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
+                       twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
        if (ret) {
                dev_err(dev, "rtc_set_alarm error %d\n", ret);
                goto out;
@@ -410,14 +430,15 @@ out:
        return ret;
 }
 
-static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
+static irqreturn_t twl_rtc_interrupt(int irq, void *data)
 {
+       struct twl_rtc *twl_rtc = data;
        unsigned long events;
        int ret = IRQ_NONE;
        int res;
        u8 rd_reg;
 
-       res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
        if (res)
                goto out;
        /*
@@ -431,12 +452,12 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
        else
                events = RTC_IRQF | RTC_PF;
 
-       res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,
-                                  REG_RTC_STATUS_REG);
+       res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M,
+                              REG_RTC_STATUS_REG);
        if (res)
                goto out;
 
-       if (twl_class_is_4030()) {
+       if (twl_rtc->class == TWL_4030) {
                /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
                 * needs 2 reads to clear the interrupt. One read is done in
                 * do_twl_pwrirq(). Doing the second read, to clear
@@ -455,7 +476,7 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
        }
 
        /* Notify RTC core on event */
-       rtc_update_irq(rtc, 1, events);
+       rtc_update_irq(twl_rtc->rtc, 1, events);
 
        ret = IRQ_HANDLED;
 out:
@@ -474,21 +495,36 @@ static const struct rtc_class_ops twl_rtc_ops = {
 
 static int twl_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_device *rtc;
+       struct twl_rtc *twl_rtc;
+       struct device_node *np = pdev->dev.of_node;
        int ret = -EINVAL;
        int irq = platform_get_irq(pdev, 0);
        u8 rd_reg;
 
+       if (!np) {
+               dev_err(&pdev->dev, "no DT info\n");
+               return -EINVAL;
+       }
+
        if (irq <= 0)
                return ret;
 
-       /* Initialize the register map */
-       if (twl_class_is_4030())
-               rtc_reg_map = (u8 *)twl4030_rtc_reg_map;
-       else
-               rtc_reg_map = (u8 *)twl6030_rtc_reg_map;
+       twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL);
+       if (!twl_rtc)
+               return -ENOMEM;
 
-       ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       if (twl_class_is_4030()) {
+               twl_rtc->class = TWL_4030;
+               twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map;
+       } else if (twl_class_is_6030()) {
+               twl_rtc->class = TWL_6030;
+               twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map;
+       } else {
+               dev_err(&pdev->dev, "TWL Class not supported.\n");
+               return -EINVAL;
+       }
+
+       ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
        if (ret < 0)
                return ret;
 
@@ -499,11 +535,11 @@ static int twl_rtc_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
 
        /* Clear RTC Power up reset and pending alarm interrupts */
-       ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+       ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG);
        if (ret < 0)
                return ret;
 
-       if (twl_class_is_6030()) {
+       if (twl_rtc->class == TWL_6030) {
                twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
                        REG_INT_MSK_LINE_A);
                twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
@@ -511,40 +547,42 @@ static int twl_rtc_probe(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "Enabling TWL-RTC\n");
-       ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);
+       ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
+                              REG_RTC_CTRL_REG);
        if (ret < 0)
                return ret;
 
        /* ensure interrupts are disabled, bootloaders can be strange */
-       ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG);
+       ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG);
        if (ret < 0)
                dev_warn(&pdev->dev, "unable to disable interrupt\n");
 
        /* init cached IRQ enable bits */
-       ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+       ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits,
+                             REG_RTC_INTERRUPTS_REG);
        if (ret < 0)
                return ret;
 
+       platform_set_drvdata(pdev, twl_rtc);
        device_init_wakeup(&pdev->dev, 1);
 
-       rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+       twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                        &twl_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
+       if (IS_ERR(twl_rtc->rtc)) {
                dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
-                       PTR_ERR(rtc));
-               return PTR_ERR(rtc);
+                       PTR_ERR(twl_rtc->rtc));
+               return PTR_ERR(twl_rtc->rtc);
        }
 
        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                        twl_rtc_interrupt,
                                        IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                       dev_name(&rtc->dev), rtc);
+                                       dev_name(&twl_rtc->rtc->dev), twl_rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "IRQ is not free.\n");
                return ret;
        }
 
-       platform_set_drvdata(pdev, rtc);
        return 0;
 }
 
@@ -554,10 +592,12 @@ static int twl_rtc_probe(struct platform_device *pdev)
  */
 static int twl_rtc_remove(struct platform_device *pdev)
 {
+       struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
+
        /* leave rtc running, but disable irqs */
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-       if (twl_class_is_6030()) {
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       if (twl_rtc->class == TWL_6030) {
                twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
                        REG_INT_MSK_LINE_A);
                twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
@@ -569,40 +609,40 @@ static int twl_rtc_remove(struct platform_device *pdev)
 
 static void twl_rtc_shutdown(struct platform_device *pdev)
 {
+       struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
+
        /* mask timer interrupts, but leave alarm interrupts on to enable
           power-on when alarm is triggered */
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
 }
 
 #ifdef CONFIG_PM_SLEEP
-static unsigned char irqstat;
-
 static int twl_rtc_suspend(struct device *dev)
 {
-       irqstat = rtc_irq_bits;
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
+       twl_rtc->irqstat = twl_rtc->rtc_irq_bits;
 
-       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
        return 0;
 }
 
 static int twl_rtc_resume(struct device *dev)
 {
-       set_rtc_irq_bit(irqstat);
+       struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
+
+       set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat);
        return 0;
 }
 #endif
 
 static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
 
-#ifdef CONFIG_OF
 static const struct of_device_id twl_rtc_of_match[] = {
        {.compatible = "ti,twl4030-rtc", },
        { },
 };
 MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
-#endif
-
-MODULE_ALIAS("platform:twl_rtc");
 
 static struct platform_driver twl4030rtc_driver = {
        .probe          = twl_rtc_probe,
@@ -611,7 +651,7 @@ static struct platform_driver twl4030rtc_driver = {
        .driver         = {
                .name           = "twl_rtc",
                .pm             = &twl_rtc_pm_ops,
-               .of_match_table = of_match_ptr(twl_rtc_of_match),
+               .of_match_table = twl_rtc_of_match,
        },
 };
 
index e173afe9266109f4e7b948433d4d422e90bacc72..0093ea2512a85809e16605088074a8335513e81c 100644 (file)
@@ -1478,6 +1478,10 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
                inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
        else
                ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+       if (i_size_read(inode) < 0) {
+               ret = -EFSCORRUPTED;
+               goto bad_inode;
+       }
        ei->i_dtime = 0;
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_state = 0;
index 741077deef3b5544dd71ae9635facb8ac1a228a9..a3645249f7ecfa4cbdae8434bb87b47ffd02dbb1 100644 (file)
@@ -150,12 +150,10 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
  */
 void fsnotify_unmount_inodes(struct super_block *sb)
 {
-       struct inode *inode, *next_i, *need_iput = NULL;
+       struct inode *inode, *iput_inode = NULL;
 
        spin_lock(&sb->s_inode_list_lock);
-       list_for_each_entry_safe(inode, next_i, &sb->s_inodes, i_sb_list) {
-               struct inode *need_iput_tmp;
-
+       list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                /*
                 * We cannot __iget() an inode in state I_FREEING,
                 * I_WILL_FREE, or I_NEW which is fine because by that point
@@ -178,49 +176,24 @@ void fsnotify_unmount_inodes(struct super_block *sb)
                        continue;
                }
 
-               need_iput_tmp = need_iput;
-               need_iput = NULL;
-
-               /* In case fsnotify_inode_delete() drops a reference. */
-               if (inode != need_iput_tmp)
-                       __iget(inode);
-               else
-                       need_iput_tmp = NULL;
+               __iget(inode);
                spin_unlock(&inode->i_lock);
-
-               /* In case the dropping of a reference would nuke next_i. */
-               while (&next_i->i_sb_list != &sb->s_inodes) {
-                       spin_lock(&next_i->i_lock);
-                       if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) &&
-                                               atomic_read(&next_i->i_count)) {
-                               __iget(next_i);
-                               need_iput = next_i;
-                               spin_unlock(&next_i->i_lock);
-                               break;
-                       }
-                       spin_unlock(&next_i->i_lock);
-                       next_i = list_next_entry(next_i, i_sb_list);
-               }
-
-               /*
-                * We can safely drop s_inode_list_lock here because either
-                * we actually hold references on both inode and next_i or
-                * end of list.  Also no new inodes will be added since the
-                * umount has begun.
-                */
                spin_unlock(&sb->s_inode_list_lock);
 
-               if (need_iput_tmp)
-                       iput(need_iput_tmp);
+               if (iput_inode)
+                       iput(iput_inode);
 
                /* for each watch, send FS_UNMOUNT and then remove it */
                fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
 
                fsnotify_inode_delete(inode);
 
-               iput(inode);
+               iput_inode = inode;
 
                spin_lock(&sb->s_inode_list_lock);
        }
        spin_unlock(&sb->s_inode_list_lock);
+
+       if (iput_inode)
+               iput(iput_inode);
 }
index 87e577a49b0d567550e09912c179a719a7ee692c..cec495a921e32cbbd4ff5bd5d2944bbf5c93f09b 100644 (file)
@@ -634,7 +634,15 @@ static void qsync_work_fn(struct work_struct *work)
                                                      dqi_sync_work.work);
        struct super_block *sb = oinfo->dqi_gqinode->i_sb;
 
-       dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
+       /*
+        * We have to be careful here not to deadlock on s_umount as umount
+        * disabling quotas may be in progress and it waits for this work to
+        * complete. If trylock fails, we'll do the sync next time...
+        */
+       if (down_read_trylock(&sb->s_umount)) {
+               dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
+               up_read(&sb->s_umount);
+       }
        schedule_delayed_work(&oinfo->dqi_sync_work,
                              msecs_to_jiffies(oinfo->dqi_syncms));
 }
index 8a54fd8a4fa57a76f7e0389ec8d875108c59e3a1..32c5a40c1257ecda129944a1abf4cdac83a2e8a1 100644 (file)
@@ -454,7 +454,7 @@ out:
 /* Sync changes in local quota file into global quota file and
  * reinitialize local quota file.
  * The function expects local quota file to be already locked and
- * dqonoff_mutex locked. */
+ * s_umount locked in shared mode. */
 static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                          int type,
                                          struct ocfs2_quota_recovery *rec)
@@ -597,7 +597,7 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
        printk(KERN_NOTICE "ocfs2: Finishing quota recovery on device (%s) for "
               "slot %u\n", osb->dev_str, slot_num);
 
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       down_read(&sb->s_umount);
        for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (list_empty(&(rec->r_list[type])))
                        continue;
@@ -674,7 +674,7 @@ out_put:
                        break;
        }
 out:
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+       up_read(&sb->s_umount);
        kfree(rec);
        return status;
 }
@@ -840,7 +840,10 @@ static int ocfs2_local_free_info(struct super_block *sb, int type)
        }
        ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
 
-       /* dqonoff_mutex protects us against racing with recovery thread... */
+       /*
+        * s_umount held in exclusive mode protects us against racing with
+        * recovery thread...
+        */
        if (oinfo->dqi_rec) {
                ocfs2_free_quota_recovery(oinfo->dqi_rec);
                mark_clean = 0;
index c894d945b084d71d7672f588d561acccf143be43..a24e42f953418b1d675481ed826d47106c1730f4 100644 (file)
@@ -985,7 +985,6 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
        for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!sb_has_quota_loaded(sb, type))
                        continue;
-               /* Cancel periodic syncing before we grab dqonoff_mutex */
                oinfo = sb_dqinfo(sb, type)->dqi_priv;
                cancel_delayed_work_sync(&oinfo->dqi_sync_work);
                inode = igrab(sb->s_dquot.files[type]);
index 8738a0d62c095021fe39208f8ec6cf4a18beab70..406fed92362a3da805b7f1834268acd2e996d46f 100644 (file)
  * spinlock to internal buffers before writing.
  *
  * Lock ordering (including related VFS locks) is the following:
- *   dqonoff_mutex > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
- * dqonoff_mutex > i_mutex comes from dquot_quota_sync, dquot_enable, etc.
+ *   s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
  */
 
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock);
@@ -572,7 +571,8 @@ int dquot_scan_active(struct super_block *sb,
        struct dquot *dquot, *old_dquot = NULL;
        int ret = 0;
 
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
+       WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));
+
        spin_lock(&dq_list_lock);
        list_for_each_entry(dquot, &inuse_list, dq_inuse) {
                if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
@@ -603,7 +603,6 @@ int dquot_scan_active(struct super_block *sb,
        spin_unlock(&dq_list_lock);
 out:
        dqput(old_dquot);
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return ret;
 }
 EXPORT_SYMBOL(dquot_scan_active);
@@ -617,7 +616,8 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
        int cnt;
        int err, ret = 0;
 
-       mutex_lock(&dqopt->dqonoff_mutex);
+       WARN_ON_ONCE(!rwsem_is_locked(&sb->s_umount));
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
@@ -653,7 +653,6 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
                    && info_dirty(&dqopt->info[cnt]))
                        sb->dq_op->write_info(sb, cnt);
        dqstats_inc(DQST_SYNCS);
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return ret;
 }
@@ -683,7 +682,6 @@ int dquot_quota_sync(struct super_block *sb, int type)
         * Now when everything is written we can discard the pagecache so
         * that userspace sees the changes.
         */
-       mutex_lock(&dqopt->dqonoff_mutex);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
@@ -693,7 +691,6 @@ int dquot_quota_sync(struct super_block *sb, int type)
                truncate_inode_pages(&dqopt->files[cnt]->i_data, 0);
                inode_unlock(dqopt->files[cnt]);
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return 0;
 }
@@ -935,7 +932,7 @@ static int dqinit_needed(struct inode *inode, int type)
        return 0;
 }
 
-/* This routine is guarded by dqonoff_mutex mutex */
+/* This routine is guarded by s_umount semaphore */
 static void add_dquot_ref(struct super_block *sb, int type)
 {
        struct inode *inode, *old_inode = NULL;
@@ -2050,21 +2047,13 @@ int dquot_get_next_id(struct super_block *sb, struct kqid *qid)
        struct quota_info *dqopt = sb_dqopt(sb);
        int err;
 
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, qid->type)) {
-               err = -ESRCH;
-               goto out;
-       }
-       if (!dqopt->ops[qid->type]->get_next_id) {
-               err = -ENOSYS;
-               goto out;
-       }
+       if (!sb_has_quota_active(sb, qid->type))
+               return -ESRCH;
+       if (!dqopt->ops[qid->type]->get_next_id)
+               return -ENOSYS;
        mutex_lock(&dqopt->dqio_mutex);
        err = dqopt->ops[qid->type]->get_next_id(sb, qid);
        mutex_unlock(&dqopt->dqio_mutex);
-out:
-       mutex_unlock(&dqopt->dqonoff_mutex);
-
        return err;
 }
 EXPORT_SYMBOL(dquot_get_next_id);
@@ -2107,6 +2096,10 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
        struct quota_info *dqopt = sb_dqopt(sb);
        struct inode *toputinode[MAXQUOTAS];
 
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
+
        /* Cannot turn off usage accounting without turning off limits, or
         * suspend quotas and simultaneously turn quotas off. */
        if ((flags & DQUOT_USAGE_ENABLED && !(flags & DQUOT_LIMITS_ENABLED))
@@ -2114,18 +2107,14 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
            DQUOT_USAGE_ENABLED)))
                return -EINVAL;
 
-       /* We need to serialize quota_off() for device */
-       mutex_lock(&dqopt->dqonoff_mutex);
-
        /*
         * Skip everything if there's nothing to do. We have to do this because
         * sometimes we are called when fill_super() failed and calling
         * sync_fs() in such cases does no good.
         */
-       if (!sb_any_quota_loaded(sb)) {
-               mutex_unlock(&dqopt->dqonoff_mutex);
+       if (!sb_any_quota_loaded(sb))
                return 0;
-       }
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                toputinode[cnt] = NULL;
                if (type != -1 && cnt != type)
@@ -2179,7 +2168,6 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
                dqopt->info[cnt].dqi_bgrace = 0;
                dqopt->ops[cnt] = NULL;
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        /* Skip syncing and setting flags if quota files are hidden */
        if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
@@ -2196,20 +2184,14 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)
         * must also discard the blockdev buffers so that we see the
         * changes done by userspace on the next quotaon() */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (toputinode[cnt]) {
-                       mutex_lock(&dqopt->dqonoff_mutex);
-                       /* If quota was reenabled in the meantime, we have
-                        * nothing to do */
-                       if (!sb_has_quota_loaded(sb, cnt)) {
-                               inode_lock(toputinode[cnt]);
-                               toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
+               /* This can happen when suspending quotas on remount-ro... */
+               if (toputinode[cnt] && !sb_has_quota_loaded(sb, cnt)) {
+                       inode_lock(toputinode[cnt]);
+                       toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
                                  S_NOATIME | S_NOQUOTA);
-                               truncate_inode_pages(&toputinode[cnt]->i_data,
-                                                    0);
-                               inode_unlock(toputinode[cnt]);
-                               mark_inode_dirty_sync(toputinode[cnt]);
-                       }
-                       mutex_unlock(&dqopt->dqonoff_mutex);
+                       truncate_inode_pages(&toputinode[cnt]->i_data, 0);
+                       inode_unlock(toputinode[cnt]);
+                       mark_inode_dirty_sync(toputinode[cnt]);
                }
        if (sb->s_bdev)
                invalidate_bdev(sb->s_bdev);
@@ -2281,6 +2263,10 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                error = -EINVAL;
                goto out_fmt;
        }
+       if (sb_has_quota_loaded(sb, type)) {
+               error = -EBUSY;
+               goto out_fmt;
+       }
 
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
                /* As we bypass the pagecache we must now flush all the
@@ -2292,11 +2278,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                sync_filesystem(sb);
                invalidate_bdev(sb->s_bdev);
        }
-       mutex_lock(&dqopt->dqonoff_mutex);
-       if (sb_has_quota_loaded(sb, type)) {
-               error = -EBUSY;
-               goto out_lock;
-       }
 
        if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
                /* We don't want quota and atime on quota files (deadlocks
@@ -2317,7 +2298,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        error = -EIO;
        dqopt->files[type] = igrab(inode);
        if (!dqopt->files[type])
-               goto out_lock;
+               goto out_file_flags;
        error = -EINVAL;
        if (!fmt->qf_ops->check_quota_file(sb, type))
                goto out_file_init;
@@ -2340,14 +2321,13 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        spin_unlock(&dq_state_lock);
 
        add_dquot_ref(sb, type);
-       mutex_unlock(&dqopt->dqonoff_mutex);
 
        return 0;
 
 out_file_init:
        dqopt->files[type] = NULL;
        iput(inode);
-out_lock:
+out_file_flags:
        if (oldflags != -1) {
                inode_lock(inode);
                /* Set the flags back (in the case of accidental quotaon()
@@ -2356,7 +2336,6 @@ out_lock:
                inode->i_flags |= oldflags;
                inode_unlock(inode);
        }
-       mutex_unlock(&dqopt->dqonoff_mutex);
 out_fmt:
        put_quota_format(fmt);
 
@@ -2371,15 +2350,16 @@ int dquot_resume(struct super_block *sb, int type)
        int ret = 0, cnt;
        unsigned int flags;
 
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
-
-               mutex_lock(&dqopt->dqonoff_mutex);
-               if (!sb_has_quota_suspended(sb, cnt)) {
-                       mutex_unlock(&dqopt->dqonoff_mutex);
+               if (!sb_has_quota_suspended(sb, cnt))
                        continue;
-               }
+
                inode = dqopt->files[cnt];
                dqopt->files[cnt] = NULL;
                spin_lock(&dq_state_lock);
@@ -2388,7 +2368,6 @@ int dquot_resume(struct super_block *sb, int type)
                                                        cnt);
                dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt);
                spin_unlock(&dq_state_lock);
-               mutex_unlock(&dqopt->dqonoff_mutex);
 
                flags = dquot_generic_flag(flags, cnt);
                ret = vfs_load_quota_inode(inode, cnt,
@@ -2424,42 +2403,30 @@ EXPORT_SYMBOL(dquot_quota_on);
 int dquot_enable(struct inode *inode, int type, int format_id,
                 unsigned int flags)
 {
-       int ret = 0;
        struct super_block *sb = inode->i_sb;
-       struct quota_info *dqopt = sb_dqopt(sb);
 
        /* Just unsuspend quotas? */
        BUG_ON(flags & DQUOT_SUSPENDED);
+       /* s_umount should be held in exclusive mode */
+       if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
+               up_read(&sb->s_umount);
 
        if (!flags)
                return 0;
        /* Just updating flags needed? */
        if (sb_has_quota_loaded(sb, type)) {
-               mutex_lock(&dqopt->dqonoff_mutex);
-               /* Now do a reliable test... */
-               if (!sb_has_quota_loaded(sb, type)) {
-                       mutex_unlock(&dqopt->dqonoff_mutex);
-                       goto load_quota;
-               }
                if (flags & DQUOT_USAGE_ENABLED &&
-                   sb_has_quota_usage_enabled(sb, type)) {
-                       ret = -EBUSY;
-                       goto out_lock;
-               }
+                   sb_has_quota_usage_enabled(sb, type))
+                       return -EBUSY;
                if (flags & DQUOT_LIMITS_ENABLED &&
-                   sb_has_quota_limits_enabled(sb, type)) {
-                       ret = -EBUSY;
-                       goto out_lock;
-               }
+                   sb_has_quota_limits_enabled(sb, type))
+                       return -EBUSY;
                spin_lock(&dq_state_lock);
                sb_dqopt(sb)->flags |= dquot_state_flag(flags, type);
                spin_unlock(&dq_state_lock);
-out_lock:
-               mutex_unlock(&dqopt->dqonoff_mutex);
-               return ret;
+               return 0;
        }
 
-load_quota:
        return vfs_load_quota_inode(inode, type, format_id, flags);
 }
 EXPORT_SYMBOL(dquot_enable);
@@ -2751,7 +2718,6 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state)
        struct quota_info *dqopt = sb_dqopt(sb);
        int type;
   
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        memset(state, 0, sizeof(*state));
        for (type = 0; type < MAXQUOTAS; type++) {
                if (!sb_has_quota_active(sb, type))
@@ -2773,7 +2739,6 @@ int dquot_get_state(struct super_block *sb, struct qc_state *state)
                tstate->nextents = 1;   /* We don't know... */
                spin_unlock(&dq_data_lock);
        }
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
 EXPORT_SYMBOL(dquot_get_state);
@@ -2787,18 +2752,13 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii)
        if ((ii->i_fieldmask & QC_WARNS_MASK) ||
            (ii->i_fieldmask & QC_RT_SPC_TIMER))
                return -EINVAL;
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               err = -ESRCH;
-               goto out;
-       }
+       if (!sb_has_quota_active(sb, type))
+               return -ESRCH;
        mi = sb_dqopt(sb)->info + type;
        if (ii->i_fieldmask & QC_FLAGS) {
                if ((ii->i_flags & QCI_ROOT_SQUASH &&
-                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD))
+                       return -EINVAL;
        }
        spin_lock(&dq_data_lock);
        if (ii->i_fieldmask & QC_SPC_TIMER)
@@ -2815,8 +2775,6 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii)
        mark_info_dirty(sb, type);
        /* Force write to disk */
        sb->dq_op->write_info(sb, type);
-out:
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return err;
 }
 EXPORT_SYMBOL(dquot_set_dqinfo);
index 5acd0c4769afa878f4435205cccb68897b81b035..07e08c7d05cae23d92ab891cb384e5dda90509df 100644 (file)
@@ -104,13 +104,9 @@ static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
 {
        __u32 fmt;
 
-       mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
+       if (!sb_has_quota_active(sb, type))
                return -ESRCH;
-       }
        fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
-       mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        if (copy_to_user(addr, &fmt, sizeof(fmt)))
                return -EFAULT;
        return 0;
@@ -789,9 +785,14 @@ static int quotactl_cmd_write(int cmd)
        }
        return 1;
 }
-
 #endif /* CONFIG_BLOCK */
 
+/* Return true if quotactl command is manipulating quota on/off state */
+static bool quotactl_cmd_onoff(int cmd)
+{
+       return (cmd == Q_QUOTAON) || (cmd == Q_QUOTAOFF);
+}
+
 /*
  * look up a superblock on which quota ops will be performed
  * - use the name of a block device to find the superblock thereon
@@ -809,7 +810,9 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
        putname(tmp);
        if (IS_ERR(bdev))
                return ERR_CAST(bdev);
-       if (quotactl_cmd_write(cmd))
+       if (quotactl_cmd_onoff(cmd))
+               sb = get_super_exclusive_thawed(bdev);
+       else if (quotactl_cmd_write(cmd))
                sb = get_super_thawed(bdev);
        else
                sb = get_super(bdev);
@@ -872,7 +875,10 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
 
        ret = do_quotactl(sb, type, cmds, id, addr, pathp);
 
-       drop_super(sb);
+       if (!quotactl_cmd_onoff(cmds))
+               drop_super(sb);
+       else
+               drop_super_exclusive(sb);
 out:
        if (pathp && !IS_ERR(pathp))
                path_put(pathp);
index c183835566c19c56fd30d6a1c22d380d10668411..1709ed029a2cae70c3d4a6cccccca760a0ad003f 100644 (file)
@@ -244,7 +244,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
        mutex_init(&s->s_vfs_rename_mutex);
        lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
        mutex_init(&s->s_dquot.dqio_mutex);
-       mutex_init(&s->s_dquot.dqonoff_mutex);
        s->s_maxbytes = MAX_NON_LFS;
        s->s_op = &default_op;
        s->s_time_gran = 1000000000;
@@ -558,6 +557,13 @@ void drop_super(struct super_block *sb)
 
 EXPORT_SYMBOL(drop_super);
 
+void drop_super_exclusive(struct super_block *sb)
+{
+       up_write(&sb->s_umount);
+       put_super(sb);
+}
+EXPORT_SYMBOL(drop_super_exclusive);
+
 /**
  *     iterate_supers - call function for all active superblocks
  *     @f: function to call
@@ -628,15 +634,7 @@ void iterate_supers_type(struct file_system_type *type,
 
 EXPORT_SYMBOL(iterate_supers_type);
 
-/**
- *     get_super - get the superblock of a device
- *     @bdev: device to get the superblock for
- *     
- *     Scans the superblock list and finds the superblock of the file system
- *     mounted on the device given. %NULL is returned if no match is found.
- */
-
-struct super_block *get_super(struct block_device *bdev)
+static struct super_block *__get_super(struct block_device *bdev, bool excl)
 {
        struct super_block *sb;
 
@@ -651,11 +649,17 @@ rescan:
                if (sb->s_bdev == bdev) {
                        sb->s_count++;
                        spin_unlock(&sb_lock);
-                       down_read(&sb->s_umount);
+                       if (!excl)
+                               down_read(&sb->s_umount);
+                       else
+                               down_write(&sb->s_umount);
                        /* still alive? */
                        if (sb->s_root && (sb->s_flags & MS_BORN))
                                return sb;
-                       up_read(&sb->s_umount);
+                       if (!excl)
+                               up_read(&sb->s_umount);
+                       else
+                               up_write(&sb->s_umount);
                        /* nope, got unmounted */
                        spin_lock(&sb_lock);
                        __put_super(sb);
@@ -666,31 +670,66 @@ rescan:
        return NULL;
 }
 
-EXPORT_SYMBOL(get_super);
-
 /**
- *     get_super_thawed - get thawed superblock of a device
+ *     get_super - get the superblock of a device
  *     @bdev: device to get the superblock for
  *
  *     Scans the superblock list and finds the superblock of the file system
- *     mounted on the device. The superblock is returned once it is thawed
- *     (or immediately if it was not frozen). %NULL is returned if no match
- *     is found.
+ *     mounted on the device given. %NULL is returned if no match is found.
  */
-struct super_block *get_super_thawed(struct block_device *bdev)
+struct super_block *get_super(struct block_device *bdev)
+{
+       return __get_super(bdev, false);
+}
+EXPORT_SYMBOL(get_super);
+
+static struct super_block *__get_super_thawed(struct block_device *bdev,
+                                             bool excl)
 {
        while (1) {
-               struct super_block *s = get_super(bdev);
+               struct super_block *s = __get_super(bdev, excl);
                if (!s || s->s_writers.frozen == SB_UNFROZEN)
                        return s;
-               up_read(&s->s_umount);
+               if (!excl)
+                       up_read(&s->s_umount);
+               else
+                       up_write(&s->s_umount);
                wait_event(s->s_writers.wait_unfrozen,
                           s->s_writers.frozen == SB_UNFROZEN);
                put_super(s);
        }
 }
+
+/**
+ *     get_super_thawed - get thawed superblock of a device
+ *     @bdev: device to get the superblock for
+ *
+ *     Scans the superblock list and finds the superblock of the file system
+ *     mounted on the device. The superblock is returned once it is thawed
+ *     (or immediately if it was not frozen). %NULL is returned if no match
+ *     is found.
+ */
+struct super_block *get_super_thawed(struct block_device *bdev)
+{
+       return __get_super_thawed(bdev, false);
+}
 EXPORT_SYMBOL(get_super_thawed);
 
+/**
+ *     get_super_exclusive_thawed - get thawed superblock of a device
+ *     @bdev: device to get the superblock for
+ *
+ *     Scans the superblock list and finds the superblock of the file system
+ *     mounted on the device. The superblock is returned once it is thawed
+ *     (or immediately if it was not frozen) and s_umount semaphore is held
+ *     in exclusive mode. %NULL is returned if no match is found.
+ */
+struct super_block *get_super_exclusive_thawed(struct block_device *bdev)
+{
+       return __get_super_thawed(bdev, true);
+}
+EXPORT_SYMBOL(get_super_exclusive_thawed);
+
 /**
  * get_active_super - get an active reference to the superblock of a device
  * @bdev: device to get the superblock for
index 22acee76cf4cd49493116621a3b30ed53f2034af..2ab7bf53d529acf95fbdf7ddbc338b0dae6b5755 100644 (file)
@@ -101,7 +101,6 @@ enum cpuhp_state {
        CPUHP_AP_ARM_L2X0_STARTING,
        CPUHP_AP_ARM_ARCH_TIMER_STARTING,
        CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
-       CPUHP_AP_DUMMY_TIMER_STARTING,
        CPUHP_AP_JCORE_TIMER_STARTING,
        CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
        CPUHP_AP_ARM_TWD_STARTING,
@@ -115,6 +114,8 @@ enum cpuhp_state {
        CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
        CPUHP_AP_KVM_ARM_VGIC_STARTING,
        CPUHP_AP_KVM_ARM_TIMER_STARTING,
+       /* Must be the last timer callback */
+       CPUHP_AP_DUMMY_TIMER_STARTING,
        CPUHP_AP_ARM_XEN_STARTING,
        CPUHP_AP_ARM_CORESIGHT_STARTING,
        CPUHP_AP_ARM_CORESIGHT4_STARTING,
index da7fbf1cdd5613cb709c1a50fa44d2e2e7159d91..c717f5ea88cb7e7f04471f34ac14bcf9bc75a4d1 100644 (file)
@@ -722,6 +722,11 @@ void init_cpu_present(const struct cpumask *src);
 void init_cpu_possible(const struct cpumask *src);
 void init_cpu_online(const struct cpumask *src);
 
+static inline void reset_cpu_possible_mask(void)
+{
+       bitmap_zero(cpumask_bits(&__cpu_possible_mask), NR_CPUS);
+}
+
 static inline void
 set_cpu_possible(unsigned int cpu, bool possible)
 {
index e6e4146bf9ae5ee9def7da466f369127895713df..2ba074328894cea30d6273a574417d789fae271d 100644 (file)
@@ -2903,8 +2903,10 @@ extern void put_filesystem(struct file_system_type *fs);
 extern struct file_system_type *get_fs_type(const char *name);
 extern struct super_block *get_super(struct block_device *);
 extern struct super_block *get_super_thawed(struct block_device *);
+extern struct super_block *get_super_exclusive_thawed(struct block_device *bdev);
 extern struct super_block *get_active_super(struct block_device *bdev);
 extern void drop_super(struct super_block *sb);
+extern void drop_super_exclusive(struct super_block *sb);
 extern void iterate_supers(void (*)(struct super_block *, void *), void *);
 extern void iterate_supers_type(struct file_system_type *,
                                void (*)(struct super_block *, void *), void *);
index 0eb7c2e7f0d633b577169fe46dca6767a0c9c415..7f6952f8d6aad7281f5403364bcfc13bdd30d36d 100644 (file)
@@ -11,6 +11,7 @@
 #define _LINUX_IMA_H
 
 #include <linux/fs.h>
+#include <linux/kexec.h>
 struct linux_binprm;
 
 #ifdef CONFIG_IMA
@@ -23,6 +24,10 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
                              enum kernel_read_file_id id);
 extern void ima_post_path_mknod(struct dentry *dentry);
 
+#ifdef CONFIG_IMA_KEXEC
+extern void ima_add_kexec_buffer(struct kimage *image);
+#endif
+
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 {
@@ -62,6 +67,13 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
 
 #endif /* CONFIG_IMA */
 
+#ifndef CONFIG_IMA_KEXEC
+struct kimage;
+
+static inline void ima_add_kexec_buffer(struct kimage *image)
+{}
+#endif
+
 #ifdef CONFIG_IMA_APPRAISE
 extern void ima_inode_post_setattr(struct dentry *dentry);
 extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
index fec597fb34cbb10e8b7b8a873c6c0e9395c60595..a4860bc9b73d4ffe927d087c24b70970084ff330 100644 (file)
@@ -115,6 +115,8 @@ enum {
 #define AXP806_CLDO2_V_CTRL            0x25
 #define AXP806_CLDO3_V_CTRL            0x26
 #define AXP806_VREF_TEMP_WARN_L                0xf3
+#define AXP806_BUS_ADDR_EXT            0xfe
+#define AXP806_REG_ADDR_EXT            0xff
 
 /* Interrupt */
 #define AXP152_IRQ1_EN                 0x40
@@ -226,6 +228,10 @@ enum {
 #define AXP20X_OCV_MAX                 0xf
 
 /* AXP22X specific registers */
+#define AXP22X_PMIC_ADC_H              0x56
+#define AXP22X_PMIC_ADC_L              0x57
+#define AXP22X_TS_ADC_H                        0x58
+#define AXP22X_TS_ADC_L                        0x59
 #define AXP22X_BATLOW_THRES1           0xe6
 
 /* AXP288 specific registers */
index 8e1cdbef3dad05e3d2665f2b12c9e9128ed75583..2c0127cb06c590f0ed3a13cdf5d890c477ebb6f5 100644 (file)
@@ -28,8 +28,6 @@
 #include <linux/mfd/core.h>
 #include <linux/platform_data/edma.h>
 
-#include <mach/hardware.h>
-
 struct regmap;
 
 /*
@@ -99,8 +97,6 @@ struct davinci_vcif {
        dma_addr_t dma_rx_addr;
 };
 
-struct davinci_vc;
-
 struct davinci_vc {
        /* Device data */
        struct device *dev;
index cf619dbeace285ee0ad2b9fc3b5e479604e42174..956caa0628f5e4e6f2daf1fbf1b4c4c491b59c11 100644 (file)
@@ -26,6 +26,7 @@ struct intel_soc_pmic {
        struct regmap *regmap;
        struct regmap_irq_chip_data *irq_chip_data;
        struct regmap_irq_chip_data *irq_chip_data_level2;
+       struct regmap_irq_chip_data *irq_chip_data_tmu;
        struct device *dev;
 };
 
index 6d435a3c06bcc6f7804181966c5e7e4f9a119caf..83701ef7d3c7bfbb1dc59f6e92a6f0664a7c48c5 100644 (file)
@@ -290,6 +290,7 @@ enum rk818_reg {
 #define SWITCH2_EN     BIT(6)
 #define SWITCH1_EN     BIT(5)
 #define DEV_OFF_RST    BIT(3)
+#define DEV_OFF                BIT(0)
 
 #define VB_LO_ACT              BIT(4)
 #define VB_LO_SEL_3500MV       (7 << 0)
index cadc6543909d96ef553bcde9935bfecaaca42a26..e5a6cdeb77dbcc5e8603199bb6021bdc17f8516c 100644 (file)
 #define RN5T618_DC3CTL2                        0x31
 #define RN5T618_DC4CTL                 0x32
 #define RN5T618_DC4CTL2                        0x33
+#define RN5T618_DC5CTL                 0x34
+#define RN5T618_DC5CTL2                        0x35
 #define RN5T618_DC1DAC                 0x36
 #define RN5T618_DC2DAC                 0x37
 #define RN5T618_DC3DAC                 0x38
 #define RN5T618_DC4DAC                 0x39
+#define RN5T618_DC5DAC                 0x3a
 #define RN5T618_DC1DAC_SLP             0x3b
 #define RN5T618_DC2DAC_SLP             0x3c
 #define RN5T618_DC3DAC_SLP             0x3d
 #define RN5T618_LDO3DAC                        0x4e
 #define RN5T618_LDO4DAC                        0x4f
 #define RN5T618_LDO5DAC                        0x50
+#define RN5T618_LDO6DAC                        0x51
+#define RN5T618_LDO7DAC                        0x52
+#define RN5T618_LDO8DAC                        0x53
+#define RN5T618_LDO9DAC                        0x54
+#define RN5T618_LDO10DAC               0x55
 #define RN5T618_LDORTCDAC              0x56
 #define RN5T618_LDORTC2DAC             0x57
 #define RN5T618_LDO1DAC_SLP            0x58
@@ -231,6 +239,7 @@ enum {
 enum {
        RN5T567 = 0,
        RN5T618,
+       RC5T619,
 };
 
 struct rn5t618 {
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
new file mode 100644 (file)
index 0000000..d7a29f2
--- /dev/null
@@ -0,0 +1,94 @@
+/* Header of ADC MFD core driver for sunxi platforms
+ *
+ * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#ifndef __SUN4I_GPADC__H__
+#define __SUN4I_GPADC__H__
+
+#define SUN4I_GPADC_CTRL0                              0x00
+
+#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY(x)             ((GENMASK(7, 0) & (x)) << 24)
+#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY_MODE           BIT(23)
+#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT               BIT(22)
+#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x)           ((GENMASK(1, 0) & (x)) << 20)
+#define SUN4I_GPADC_CTRL0_FS_DIV(x)                    ((GENMASK(3, 0) & (x)) << 16)
+#define SUN4I_GPADC_CTRL0_T_ACQ(x)                     (GENMASK(15, 0) & (x))
+
+#define SUN4I_GPADC_CTRL1                              0x04
+
+#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE(x)                ((GENMASK(7, 0) & (x)) << 12)
+#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE_EN                BIT(9)
+#define SUN4I_GPADC_CTRL1_TOUCH_PAN_CALI_EN            BIT(6)
+#define SUN4I_GPADC_CTRL1_TP_DUAL_EN                   BIT(5)
+#define SUN4I_GPADC_CTRL1_TP_MODE_EN                   BIT(4)
+#define SUN4I_GPADC_CTRL1_TP_ADC_SELECT                        BIT(3)
+#define SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(x)           (GENMASK(2, 0) & (x))
+
+/* TP_CTRL1 bits for sun6i SOCs */
+#define SUN6I_GPADC_CTRL1_TOUCH_PAN_CALI_EN            BIT(7)
+#define SUN6I_GPADC_CTRL1_TP_DUAL_EN                   BIT(6)
+#define SUN6I_GPADC_CTRL1_TP_MODE_EN                   BIT(5)
+#define SUN6I_GPADC_CTRL1_TP_ADC_SELECT                        BIT(4)
+#define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x)           (GENMASK(3, 0) & BIT(x))
+
+#define SUN4I_GPADC_CTRL2                              0x08
+
+#define SUN4I_GPADC_CTRL2_TP_SENSITIVE_ADJUST(x)       ((GENMASK(3, 0) & (x)) << 28)
+#define SUN4I_GPADC_CTRL2_TP_MODE_SELECT(x)            ((GENMASK(1, 0) & (x)) << 26)
+#define SUN4I_GPADC_CTRL2_PRE_MEA_EN                   BIT(24)
+#define SUN4I_GPADC_CTRL2_PRE_MEA_THRE_CNT(x)          (GENMASK(23, 0) & (x))
+
+#define SUN4I_GPADC_CTRL3                              0x0c
+
+#define SUN4I_GPADC_CTRL3_FILTER_EN                    BIT(2)
+#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x)               (GENMASK(1, 0) & (x))
+
+#define SUN4I_GPADC_TPR                                        0x18
+
+#define SUN4I_GPADC_TPR_TEMP_ENABLE                    BIT(16)
+#define SUN4I_GPADC_TPR_TEMP_PERIOD(x)                 (GENMASK(15, 0) & (x))
+
+#define SUN4I_GPADC_INT_FIFOC                          0x10
+
+#define SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN              BIT(18)
+#define SUN4I_GPADC_INT_FIFOC_TP_OVERRUN_IRQ_EN                BIT(17)
+#define SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN           BIT(16)
+#define SUN4I_GPADC_INT_FIFOC_TP_DATA_XY_CHANGE                BIT(13)
+#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(x)    ((GENMASK(4, 0) & (x)) << 8)
+#define SUN4I_GPADC_INT_FIFOC_TP_DATA_DRQ_EN           BIT(7)
+#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH            BIT(4)
+#define SUN4I_GPADC_INT_FIFOC_TP_UP_IRQ_EN             BIT(1)
+#define SUN4I_GPADC_INT_FIFOC_TP_DOWN_IRQ_EN           BIT(0)
+
+#define SUN4I_GPADC_INT_FIFOS                          0x14
+
+#define SUN4I_GPADC_INT_FIFOS_TEMP_DATA_PENDING                BIT(18)
+#define SUN4I_GPADC_INT_FIFOS_FIFO_OVERRUN_PENDING     BIT(17)
+#define SUN4I_GPADC_INT_FIFOS_FIFO_DATA_PENDING                BIT(16)
+#define SUN4I_GPADC_INT_FIFOS_TP_IDLE_FLG              BIT(2)
+#define SUN4I_GPADC_INT_FIFOS_TP_UP_PENDING            BIT(1)
+#define SUN4I_GPADC_INT_FIFOS_TP_DOWN_PENDING          BIT(0)
+
+#define SUN4I_GPADC_CDAT                               0x1c
+#define SUN4I_GPADC_TEMP_DATA                          0x20
+#define SUN4I_GPADC_DATA                               0x24
+
+#define SUN4I_GPADC_IRQ_FIFO_DATA                      0
+#define SUN4I_GPADC_IRQ_TEMP_DATA                      1
+
+/* 10s delay before suspending the IP */
+#define SUN4I_GPADC_AUTOSUSPEND_DELAY                  10000
+
+struct sun4i_gpadc_dev {
+       struct device                   *dev;
+       struct regmap                   *regmap;
+       struct regmap_irq_chip_data     *regmap_irqc;
+       void __iomem                    *base;
+};
+
+#endif
index 3cbec4b2496a6a5cdbef0816aa92e157e8fcfd4a..eac285756b37a918c1bfb11845b2a160f559618f 100644 (file)
 #define TPS65217_PPATH_AC_CURRENT_MASK 0x0C
 #define TPS65217_PPATH_USB_CURRENT_MASK        0x03
 
-#define TPS65217_INT_RESERVEDM         BIT(7)
 #define TPS65217_INT_PBM               BIT(6)
 #define TPS65217_INT_ACM               BIT(5)
 #define TPS65217_INT_USBM              BIT(4)
 #define TPS65217_INT_PBI               BIT(2)
 #define TPS65217_INT_ACI               BIT(1)
 #define TPS65217_INT_USBI              BIT(0)
+#define TPS65217_INT_SHIFT             4
+#define TPS65217_INT_MASK              (TPS65217_INT_PBM | TPS65217_INT_ACM | \
+                                       TPS65217_INT_USBM)
 
 #define TPS65217_CHGCONFIG0_TREG       BIT(7)
 #define TPS65217_CHGCONFIG0_DPPM       BIT(6)
index d1db9527fab5897e320dffc6925017b8bc29207d..bccd2d68b1e306c741ef295f9fe73d2d9e830086 100644 (file)
@@ -282,10 +282,9 @@ struct tps65218 {
        struct regulator_desc desc[TPS65218_NUM_REGULATOR];
        struct tps_info *info[TPS65218_NUM_REGULATOR];
        struct regmap *regmap;
+       u8 *strobes;
 };
 
-int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
-                                       unsigned int *val);
 int tps65218_reg_write(struct tps65218 *tps, unsigned int reg,
                        unsigned int val, unsigned int level);
 int tps65218_set_bits(struct tps65218 *tps, unsigned int reg,
index 1a603701550e33e51dd2f4c78a5d4311abc0112a..b25d0297ba887a901da8dd5349ac777e908da533 100644 (file)
@@ -319,21 +319,7 @@ struct tps65912 {
        struct regmap_irq_chip_data *irq_data;
 };
 
-static const struct regmap_range tps65912_yes_ranges[] = {
-       regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5),
-};
-
-static const struct regmap_access_table tps65912_volatile_table = {
-       .yes_ranges = tps65912_yes_ranges,
-       .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges),
-};
-
-static const struct regmap_config tps65912_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .cache_type = REGCACHE_RBTREE,
-       .volatile_table = &tps65912_volatile_table,
-};
+extern const struct regmap_config tps65912_regmap_config;
 
 int tps65912_device_init(struct tps65912 *tps);
 int tps65912_device_exit(struct tps65912 *tps);
index 08d947fc4c59dac845652dee2ad1c98aac2f2626..808751d7b737e28cd0b933d19b6544cae85bab79 100644 (file)
@@ -509,10 +509,6 @@ struct mm_struct {
        bool tlb_flush_pending;
 #endif
        struct uprobes_state uprobes_state;
-#ifdef CONFIG_X86_INTEL_MPX
-       /* address of the bounds directory */
-       void __user *bd_addr;
-#endif
 #ifdef CONFIG_HUGETLB_PAGE
        atomic_long_t hugetlb_usage;
 #endif
index 78a98821f9d0a98780e6129b6b1f4cc9c0fc4d80..3434eef2a5aad963d579670ed081b68db382239d 100644 (file)
@@ -520,7 +520,6 @@ static inline void quota_send_warning(struct kqid qid, dev_t dev,
 struct quota_info {
        unsigned int flags;                     /* Flags for diskquotas on this device */
        struct mutex dqio_mutex;                /* lock device while I/O in progress */
-       struct mutex dqonoff_mutex;             /* Serialize quotaon & quotaoff */
        struct inode *files[MAXQUOTAS];         /* inodes of quotafiles */
        struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
        const struct quota_format_ops *ops[MAXQUOTAS];  /* Operations for each type */
index 57c9e0622a38dbd8a742015cd9742bcd52abf226..56375edf2ed22c7f32dd1d92c6b4fe59f3b42229 100644 (file)
@@ -77,8 +77,11 @@ extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
 
 #ifdef CONFIG_PRINTK
 
-#define WARN_ON_RATELIMIT(condition, state)                    \
-               WARN_ON((condition) && __ratelimit(state))
+#define WARN_ON_RATELIMIT(condition, state)    ({              \
+       bool __rtn_cond = !!(condition);                        \
+       WARN_ON(__rtn_cond && __ratelimit(state));              \
+       __rtn_cond;                                             \
+})
 
 #define WARN_RATELIMIT(condition, format, ...)                 \
 ({                                                             \
index 217fd2e7f4354140146c910f8de0607458462557..5339aca811d2289690198119206eaa42d959452f 100644 (file)
@@ -1586,7 +1586,11 @@ EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance);
  * @startup:   startup callback function
  * @teardown:  teardown callback function
  *
- * Returns 0 if successful, otherwise a proper error code
+ * Returns:
+ *   On success:
+ *      Positive state number if @state is CPUHP_AP_ONLINE_DYN
+ *      0 for all other states
+ *   On failure: proper (negative) error code
  */
 int __cpuhp_setup_state(enum cpuhp_state state,
                        const char *name, bool invoke,
index 9be9bda7c1f94cf633bb11b4be141ceecf0244b4..4544b115f5eb85d4b01ec966f933f191cd2cae1e 100644 (file)
@@ -37,10 +37,10 @@ static void irq_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk,
 
 static int get_nodes_in_cpumask(const struct cpumask *mask, nodemask_t *nodemsk)
 {
-       int n, nodes;
+       int n, nodes = 0;
 
        /* Calculate the number of nodes in the supplied affinity mask */
-       for (n = 0, nodes = 0; n < num_online_nodes(); n++) {
+       for_each_online_node(n) {
                if (cpumask_intersects(mask, cpumask_of_node(n))) {
                        node_set(n, *nodemsk);
                        nodes++;
@@ -82,7 +82,7 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
        nodes = get_nodes_in_cpumask(cpu_online_mask, &nodemsk);
 
        /*
-        * If the number of nodes in the mask is less than or equal the
+        * If the number of nodes in the mask is greater than or equal the
         * number of vectors we just spread the vectors across the nodes.
         */
        if (affv <= nodes) {
index cc2fa35ca480367fe96430ef23ec7b869974c0e7..85e5546cd791cc31261cd6deb8aea933bb41c008 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/kcov.h>
+#include <asm/setup.h>
 
 /*
  * kcov descriptor (one per opened debugfs file).
@@ -73,6 +74,11 @@ void notrace __sanitizer_cov_trace_pc(void)
        if (mode == KCOV_MODE_TRACE) {
                unsigned long *area;
                unsigned long pos;
+               unsigned long ip = _RET_IP_;
+
+#ifdef CONFIG_RANDOMIZE_BASE
+               ip -= kaslr_offset();
+#endif
 
                /*
                 * There is some code that runs in interrupts but for which
@@ -86,7 +92,7 @@ void notrace __sanitizer_cov_trace_pc(void)
                /* The first word is number of subsequent PCs. */
                pos = READ_ONCE(area[0]) + 1;
                if (likely(pos < t->kcov_size)) {
-                       area[pos] = _RET_IP_;
+                       area[pos] = ip;
                        WRITE_ONCE(area[0], pos);
                }
        }
index 0c2df7f737925b6d0bd5bf624ceb12e8a6d53d86..b56a558e406db6375bea4b07e5873a4c6f0b401e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/fs.h>
+#include <linux/ima.h>
 #include <crypto/hash.h>
 #include <crypto/sha.h>
 #include <linux/syscalls.h>
@@ -132,6 +133,9 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
                return ret;
        image->kernel_buf_len = size;
 
+       /* IMA needs to pass the measurement list to the next kernel. */
+       ima_add_kexec_buffer(image);
+
        /* Call arch image probe handlers */
        ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
                                            image->kernel_buf_len);
index f6aae7977824ab7595950e378c2dd0f0bbe0256d..d2a20e83ebaed372ddb68d00bd8f44a50989b804 100644 (file)
@@ -871,6 +871,9 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
        int cpu = smp_processor_id();
 
+       if (!bc)
+               return;
+
        /* Set it up only once ! */
        if (bc->event_handler != tick_handle_oneshot_broadcast) {
                int was_periodic = clockevent_state_periodic(bc);
index 7446097f72bd8b590ea192b9fb6c2955461c1338..cb66a46488401b6a99091b489df029c3035a79dd 100644 (file)
@@ -26,7 +26,7 @@ config CONSOLE_LOGLEVEL_DEFAULT
          the kernel bootargs. loglevel=<x> continues to override whatever
          value is specified here as well.
 
-         Note: This does not affect the log level of un-prefixed prink()
+         Note: This does not affect the log level of un-prefixed printk()
          usage in the kernel. That is controlled by the MESSAGE_LOGLEVEL_DEFAULT
          option.
 
index 6c707bfe02fde002feae9ea2fab3fc9647c3baa0..a430131125815803ba25a7014917c6118087dd5c 100644 (file)
@@ -139,7 +139,20 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
                }
 
                if (end_index >= start_index) {
-                       unsigned long count = invalidate_mapping_pages(mapping,
+                       unsigned long count;
+
+                       /*
+                        * It's common to FADV_DONTNEED right after
+                        * the read or write that instantiates the
+                        * pages, in which case there will be some
+                        * sitting on the local LRU cache. Try to
+                        * avoid the expensive remote drain and the
+                        * second cache tree walk below by flushing
+                        * them out right away.
+                        */
+                       lru_add_drain();
+
+                       count = invalidate_mapping_pages(mapping,
                                                start_index, end_index);
 
                        /*
index 5487827fa86c7f1b236521dca9d36c1805bfc1f8..370eb2f4dd379f7cf0708f17306f5a98c721443b 100644 (file)
@@ -27,6 +27,18 @@ config IMA
          to learn more about IMA.
          If unsure, say N.
 
+config IMA_KEXEC
+       bool "Enable carrying the IMA measurement list across a soft boot"
+       depends on IMA && TCG_TPM && HAVE_IMA_KEXEC
+       default n
+       help
+          TPM PCRs are only reset on a hard reboot.  In order to validate
+          a TPM's quote after a soft boot, the IMA measurement list of the
+          running kernel must be saved and restored on boot.
+
+          Depending on the IMA policy, the measurement list can grow to
+          be very large.
+
 config IMA_MEASURE_PCR_IDX
        int
        depends on IMA
index 9aeaedad1e2b9f69e89fa19750490b9ad5cdcc0b..29f198bde02b9ff12fb38b18dfda191b9c3c1e91 100644 (file)
@@ -8,4 +8,5 @@ obj-$(CONFIG_IMA) += ima.o
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
         ima_policy.o ima_template.o ima_template_lib.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
+ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
 obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
index db25f54a04fe5bd28cdd90dbb82d794bca5e9262..5e6180a4da7d2a9d583d4b81bbcfb76a1d9e558a 100644 (file)
 
 #include "../integrity.h"
 
+#ifdef CONFIG_HAVE_IMA_KEXEC
+#include <asm/ima.h>
+#endif
+
 enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_BINARY_NO_FIELD_LEN,
                     IMA_SHOW_BINARY_OLD_STRING_FMT, IMA_SHOW_ASCII };
 enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
@@ -81,6 +85,7 @@ struct ima_template_field {
 
 /* IMA template descriptor definition */
 struct ima_template_desc {
+       struct list_head list;
        char *name;
        char *fmt;
        int num_fields;
@@ -102,6 +107,27 @@ struct ima_queue_entry {
 };
 extern struct list_head ima_measurements;      /* list of all measurements */
 
+/* Some details preceding the binary serialized measurement list */
+struct ima_kexec_hdr {
+       u16 version;
+       u16 _reserved0;
+       u32 _reserved1;
+       u64 buffer_size;
+       u64 count;
+};
+
+#ifdef CONFIG_HAVE_IMA_KEXEC
+void ima_load_kexec_buffer(void);
+#else
+static inline void ima_load_kexec_buffer(void) {}
+#endif /* CONFIG_HAVE_IMA_KEXEC */
+
+/*
+ * The default binary_runtime_measurements list format is defined as the
+ * platform native format.  The canonical format is defined as little-endian.
+ */
+extern bool ima_canonical_fmt;
+
 /* Internal IMA function definitions */
 int ima_init(void);
 int ima_fs_init(void);
@@ -122,7 +148,12 @@ int ima_init_crypto(void);
 void ima_putc(struct seq_file *m, void *data, int datalen);
 void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
 struct ima_template_desc *ima_template_desc_current(void);
+int ima_restore_measurement_entry(struct ima_template_entry *entry);
+int ima_restore_measurement_list(loff_t bufsize, void *buf);
+int ima_measurements_show(struct seq_file *m, void *v);
+unsigned long ima_get_binary_runtime_size(void);
 int ima_init_template(void);
+void ima_init_template_list(void);
 
 /*
  * used to protect h_table and sha_table
index 38f2ed830dd6fb23c216b014e39405318705d8ee..802d5d20f36fe46ecb787163f4dafd532741c78b 100644 (file)
@@ -477,11 +477,13 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
                u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 };
                u8 *data_to_hash = field_data[i].data;
                u32 datalen = field_data[i].len;
+               u32 datalen_to_hash =
+                   !ima_canonical_fmt ? datalen : cpu_to_le32(datalen);
 
                if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) {
                        rc = crypto_shash_update(shash,
-                                               (const u8 *) &field_data[i].len,
-                                               sizeof(field_data[i].len));
+                                               (const u8 *) &datalen_to_hash,
+                                               sizeof(datalen_to_hash));
                        if (rc)
                                break;
                } else if (strcmp(td->fields[i]->field_id, "n") == 0) {
index 3df46906492dec72a6381aa2a6aa67500e6d7883..ca303e5d2b9403d858c9df8f5512c80040b0f3f7 100644 (file)
 
 static DEFINE_MUTEX(ima_write_mutex);
 
+bool ima_canonical_fmt;
+static int __init default_canonical_fmt_setup(char *str)
+{
+#ifdef __BIG_ENDIAN
+       ima_canonical_fmt = 1;
+#endif
+       return 1;
+}
+__setup("ima_canonical_fmt", default_canonical_fmt_setup);
+
 static int valid_policy = 1;
 #define TMPBUFLEN 12
 static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -116,13 +126,13 @@ void ima_putc(struct seq_file *m, void *data, int datalen)
  *       [eventdata length]
  *       eventdata[n]=template specific data
  */
-static int ima_measurements_show(struct seq_file *m, void *v)
+int ima_measurements_show(struct seq_file *m, void *v)
 {
        /* the list never shrinks, so we don't need a lock here */
        struct ima_queue_entry *qe = v;
        struct ima_template_entry *e;
        char *template_name;
-       int namelen;
+       u32 pcr, namelen, template_data_len; /* temporary fields */
        bool is_ima_template = false;
        int i;
 
@@ -139,25 +149,29 @@ static int ima_measurements_show(struct seq_file *m, void *v)
         * PCR used defaults to the same (config option) in
         * little-endian format, unless set in policy
         */
-       ima_putc(m, &e->pcr, sizeof(e->pcr));
+       pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
+       ima_putc(m, &pcr, sizeof(e->pcr));
 
        /* 2nd: template digest */
        ima_putc(m, e->digest, TPM_DIGEST_SIZE);
 
        /* 3rd: template name size */
-       namelen = strlen(template_name);
+       namelen = !ima_canonical_fmt ? strlen(template_name) :
+               cpu_to_le32(strlen(template_name));
        ima_putc(m, &namelen, sizeof(namelen));
 
        /* 4th:  template name */
-       ima_putc(m, template_name, namelen);
+       ima_putc(m, template_name, strlen(template_name));
 
        /* 5th:  template length (except for 'ima' template) */
        if (strcmp(template_name, IMA_TEMPLATE_IMA_NAME) == 0)
                is_ima_template = true;
 
-       if (!is_ima_template)
-               ima_putc(m, &e->template_data_len,
-                        sizeof(e->template_data_len));
+       if (!is_ima_template) {
+               template_data_len = !ima_canonical_fmt ? e->template_data_len :
+                       cpu_to_le32(e->template_data_len);
+               ima_putc(m, &template_data_len, sizeof(e->template_data_len));
+       }
 
        /* 6th:  template specific data */
        for (i = 0; i < e->template_desc->num_fields; i++) {
index 2ac1f41db5c05677007d09aac73c1fa1aa19ff03..2967d497a665c9f627af9ecf77f1554a97f5addc 100644 (file)
@@ -129,6 +129,8 @@ int __init ima_init(void)
        if (rc != 0)
                return rc;
 
+       ima_load_kexec_buffer();
+
        rc = ima_add_boot_aggregate();  /* boot aggregate must be first entry */
        if (rc != 0)
                return rc;
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
new file mode 100644 (file)
index 0000000..e473eee
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Authors:
+ * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
+ * Mimi Zohar <zohar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include <linux/kexec.h>
+#include "ima.h"
+
+#ifdef CONFIG_IMA_KEXEC
+static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
+                                    unsigned long segment_size)
+{
+       struct ima_queue_entry *qe;
+       struct seq_file file;
+       struct ima_kexec_hdr khdr;
+       int ret = 0;
+
+       /* segment size can't change between kexec load and execute */
+       file.buf = vmalloc(segment_size);
+       if (!file.buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       file.size = segment_size;
+       file.read_pos = 0;
+       file.count = sizeof(khdr);      /* reserved space */
+
+       memset(&khdr, 0, sizeof(khdr));
+       khdr.version = 1;
+       list_for_each_entry_rcu(qe, &ima_measurements, later) {
+               if (file.count < file.size) {
+                       khdr.count++;
+                       ima_measurements_show(&file, qe);
+               } else {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       if (ret < 0)
+               goto out;
+
+       /*
+        * fill in reserved space with some buffer details
+        * (eg. version, buffer size, number of measurements)
+        */
+       khdr.buffer_size = file.count;
+       if (ima_canonical_fmt) {
+               khdr.version = cpu_to_le16(khdr.version);
+               khdr.count = cpu_to_le64(khdr.count);
+               khdr.buffer_size = cpu_to_le64(khdr.buffer_size);
+       }
+       memcpy(file.buf, &khdr, sizeof(khdr));
+
+       print_hex_dump(KERN_DEBUG, "ima dump: ", DUMP_PREFIX_NONE,
+                       16, 1, file.buf,
+                       file.count < 100 ? file.count : 100, true);
+
+       *buffer_size = file.count;
+       *buffer = file.buf;
+out:
+       if (ret == -EINVAL)
+               vfree(file.buf);
+       return ret;
+}
+
+/*
+ * Called during kexec_file_load so that IMA can add a segment to the kexec
+ * image for the measurement list for the next kernel.
+ *
+ * This function assumes that kexec_mutex is held.
+ */
+void ima_add_kexec_buffer(struct kimage *image)
+{
+       struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE,
+                                 .buf_min = 0, .buf_max = ULONG_MAX,
+                                 .top_down = true };
+       unsigned long binary_runtime_size;
+
+       /* use more understandable variable names than defined in kbuf */
+       void *kexec_buffer = NULL;
+       size_t kexec_buffer_size;
+       size_t kexec_segment_size;
+       int ret;
+
+       /*
+        * Reserve an extra half page of memory for additional measurements
+        * added during the kexec load.
+        */
+       binary_runtime_size = ima_get_binary_runtime_size();
+       if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
+               kexec_segment_size = ULONG_MAX;
+       else
+               kexec_segment_size = ALIGN(ima_get_binary_runtime_size() +
+                                          PAGE_SIZE / 2, PAGE_SIZE);
+       if ((kexec_segment_size == ULONG_MAX) ||
+           ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages / 2)) {
+               pr_err("Binary measurement list too large.\n");
+               return;
+       }
+
+       ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
+                                 kexec_segment_size);
+       if (!kexec_buffer) {
+               pr_err("Not enough memory for the kexec measurement buffer.\n");
+               return;
+       }
+
+       kbuf.buffer = kexec_buffer;
+       kbuf.bufsz = kexec_buffer_size;
+       kbuf.memsz = kexec_segment_size;
+       ret = kexec_add_buffer(&kbuf);
+       if (ret) {
+               pr_err("Error passing over kexec measurement buffer.\n");
+               return;
+       }
+
+       ret = arch_ima_add_kexec_buffer(image, kbuf.mem, kexec_segment_size);
+       if (ret) {
+               pr_err("Error passing over kexec measurement buffer.\n");
+               return;
+       }
+
+       pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
+                kbuf.mem);
+}
+#endif /* IMA_KEXEC */
+
+/*
+ * Restore the measurement list from the previous kernel.
+ */
+void ima_load_kexec_buffer(void)
+{
+       void *kexec_buffer = NULL;
+       size_t kexec_buffer_size = 0;
+       int rc;
+
+       rc = ima_get_kexec_buffer(&kexec_buffer, &kexec_buffer_size);
+       switch (rc) {
+       case 0:
+               rc = ima_restore_measurement_list(kexec_buffer_size,
+                                                 kexec_buffer);
+               if (rc != 0)
+                       pr_err("Failed to restore the measurement list: %d\n",
+                               rc);
+
+               ima_free_kexec_buffer();
+               break;
+       case -ENOTSUPP:
+               pr_debug("Restoring the measurement list not supported\n");
+               break;
+       case -ENOENT:
+               pr_debug("No measurement list to restore\n");
+               break;
+       default:
+               pr_debug("Error restoring the measurement list: %d\n", rc);
+       }
+}
index 423d111b3b9475ef43092b77a744ed6fe65599ab..50818c60538b8e0e764de72c842cfb608abb305a 100644 (file)
@@ -418,6 +418,7 @@ static int __init init_ima(void)
 {
        int error;
 
+       ima_init_template_list();
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
        if (!error) {
index 32f6ac0f96dfb0ed3c8d296c817e97946834c28e..d9aa5ab712044a4d7e0a3a11ecfb86547198e3af 100644 (file)
 #define AUDIT_CAUSE_LEN_MAX 32
 
 LIST_HEAD(ima_measurements);   /* list of all measurements */
+#ifdef CONFIG_IMA_KEXEC
+static unsigned long binary_runtime_size;
+#else
+static unsigned long binary_runtime_size = ULONG_MAX;
+#endif
 
 /* key: inode (before secure-hashing a file) */
 struct ima_h_table ima_htable = {
@@ -64,12 +69,32 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
        return ret;
 }
 
+/*
+ * Calculate the memory required for serializing a single
+ * binary_runtime_measurement list entry, which contains a
+ * couple of variable length fields (e.g template name and data).
+ */
+static int get_binary_runtime_size(struct ima_template_entry *entry)
+{
+       int size = 0;
+
+       size += sizeof(u32);    /* pcr */
+       size += sizeof(entry->digest);
+       size += sizeof(int);    /* template name size field */
+       size += strlen(entry->template_desc->name) + 1;
+       size += sizeof(entry->template_data_len);
+       size += entry->template_data_len;
+       return size;
+}
+
 /* ima_add_template_entry helper function:
- * - Add template entry to measurement list and hash table.
+ * - Add template entry to the measurement list and hash table, for
+ *   all entries except those carried across kexec.
  *
  * (Called with ima_extend_list_mutex held.)
  */
-static int ima_add_digest_entry(struct ima_template_entry *entry)
+static int ima_add_digest_entry(struct ima_template_entry *entry,
+                               bool update_htable)
 {
        struct ima_queue_entry *qe;
        unsigned int key;
@@ -85,11 +110,34 @@ static int ima_add_digest_entry(struct ima_template_entry *entry)
        list_add_tail_rcu(&qe->later, &ima_measurements);
 
        atomic_long_inc(&ima_htable.len);
-       key = ima_hash_key(entry->digest);
-       hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+       if (update_htable) {
+               key = ima_hash_key(entry->digest);
+               hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
+       }
+
+       if (binary_runtime_size != ULONG_MAX) {
+               int size;
+
+               size = get_binary_runtime_size(entry);
+               binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ?
+                    binary_runtime_size + size : ULONG_MAX;
+       }
        return 0;
 }
 
+/*
+ * Return the amount of memory required for serializing the
+ * entire binary_runtime_measurement list, including the ima_kexec_hdr
+ * structure.
+ */
+unsigned long ima_get_binary_runtime_size(void)
+{
+       if (binary_runtime_size >= (ULONG_MAX - sizeof(struct ima_kexec_hdr)))
+               return ULONG_MAX;
+       else
+               return binary_runtime_size + sizeof(struct ima_kexec_hdr);
+};
+
 static int ima_pcr_extend(const u8 *hash, int pcr)
 {
        int result = 0;
@@ -103,8 +151,13 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
        return result;
 }
 
-/* Add template entry to the measurement list and hash table,
- * and extend the pcr.
+/*
+ * Add template entry to the measurement list and hash table, and
+ * extend the pcr.
+ *
+ * On systems which support carrying the IMA measurement list across
+ * kexec, maintain the total memory size required for serializing the
+ * binary_runtime_measurements.
  */
 int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                           const char *op, struct inode *inode,
@@ -126,7 +179,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                }
        }
 
-       result = ima_add_digest_entry(entry);
+       result = ima_add_digest_entry(entry, 1);
        if (result < 0) {
                audit_cause = "ENOMEM";
                audit_info = 0;
@@ -149,3 +202,13 @@ out:
                            op, audit_cause, result, audit_info);
        return result;
 }
+
+int ima_restore_measurement_entry(struct ima_template_entry *entry)
+{
+       int result = 0;
+
+       mutex_lock(&ima_extend_list_mutex);
+       result = ima_add_digest_entry(entry, 0);
+       mutex_unlock(&ima_extend_list_mutex);
+       return result;
+}
index febd12ed9b55ab4d6009176c355655c646272437..cebb37c63629fc89465cd020f2efbd550442cfc7 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/rculist.h>
 #include "ima.h"
 #include "ima_template_lib.h"
 
-static struct ima_template_desc defined_templates[] = {
+static struct ima_template_desc builtin_templates[] = {
        {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
        {.name = "ima-ng", .fmt = "d-ng|n-ng"},
        {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
        {.name = "", .fmt = ""},        /* placeholder for a custom format */
 };
 
+static LIST_HEAD(defined_templates);
+static DEFINE_SPINLOCK(template_list);
+
 static struct ima_template_field supported_fields[] = {
        {.field_id = "d", .field_init = ima_eventdigest_init,
         .field_show = ima_show_template_digest},
@@ -37,6 +41,7 @@ static struct ima_template_field supported_fields[] = {
        {.field_id = "sig", .field_init = ima_eventsig_init,
         .field_show = ima_show_template_sig},
 };
+#define MAX_TEMPLATE_NAME_LEN 15
 
 static struct ima_template_desc *ima_template;
 static struct ima_template_desc *lookup_template_desc(const char *name);
@@ -52,6 +57,8 @@ static int __init ima_template_setup(char *str)
        if (ima_template)
                return 1;
 
+       ima_init_template_list();
+
        /*
         * Verify that a template with the supplied name exists.
         * If not, use CONFIG_IMA_DEFAULT_TEMPLATE.
@@ -80,7 +87,7 @@ __setup("ima_template=", ima_template_setup);
 
 static int __init ima_template_fmt_setup(char *str)
 {
-       int num_templates = ARRAY_SIZE(defined_templates);
+       int num_templates = ARRAY_SIZE(builtin_templates);
 
        if (ima_template)
                return 1;
@@ -91,22 +98,28 @@ static int __init ima_template_fmt_setup(char *str)
                return 1;
        }
 
-       defined_templates[num_templates - 1].fmt = str;
-       ima_template = defined_templates + num_templates - 1;
+       builtin_templates[num_templates - 1].fmt = str;
+       ima_template = builtin_templates + num_templates - 1;
+
        return 1;
 }
 __setup("ima_template_fmt=", ima_template_fmt_setup);
 
 static struct ima_template_desc *lookup_template_desc(const char *name)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
-               if (strcmp(defined_templates[i].name, name) == 0)
-                       return defined_templates + i;
+       struct ima_template_desc *template_desc;
+       int found = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(template_desc, &defined_templates, list) {
+               if ((strcmp(template_desc->name, name) == 0) ||
+                   (strcmp(template_desc->fmt, name) == 0)) {
+                       found = 1;
+                       break;
+               }
        }
-
-       return NULL;
+       rcu_read_unlock();
+       return found ? template_desc : NULL;
 }
 
 static struct ima_template_field *lookup_template_field(const char *field_id)
@@ -142,9 +155,14 @@ static int template_desc_init_fields(const char *template_fmt,
 {
        const char *template_fmt_ptr;
        struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
-       int template_num_fields = template_fmt_size(template_fmt);
+       int template_num_fields;
        int i, len;
 
+       if (num_fields && *num_fields > 0) /* already initialized? */
+               return 0;
+
+       template_num_fields = template_fmt_size(template_fmt);
+
        if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) {
                pr_err("format string '%s' contains too many fields\n",
                       template_fmt);
@@ -182,11 +200,28 @@ static int template_desc_init_fields(const char *template_fmt,
        return 0;
 }
 
+void ima_init_template_list(void)
+{
+       int i;
+
+       if (!list_empty(&defined_templates))
+               return;
+
+       spin_lock(&template_list);
+       for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) {
+               list_add_tail_rcu(&builtin_templates[i].list,
+                                 &defined_templates);
+       }
+       spin_unlock(&template_list);
+}
+
 struct ima_template_desc *ima_template_desc_current(void)
 {
-       if (!ima_template)
+       if (!ima_template) {
+               ima_init_template_list();
                ima_template =
                    lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE);
+       }
        return ima_template;
 }
 
@@ -205,3 +240,239 @@ int __init ima_init_template(void)
 
        return result;
 }
+
+static struct ima_template_desc *restore_template_fmt(char *template_name)
+{
+       struct ima_template_desc *template_desc = NULL;
+       int ret;
+
+       ret = template_desc_init_fields(template_name, NULL, NULL);
+       if (ret < 0) {
+               pr_err("attempting to initialize the template \"%s\" failed\n",
+                       template_name);
+               goto out;
+       }
+
+       template_desc = kzalloc(sizeof(*template_desc), GFP_KERNEL);
+       if (!template_desc)
+               goto out;
+
+       template_desc->name = "";
+       template_desc->fmt = kstrdup(template_name, GFP_KERNEL);
+       if (!template_desc->fmt)
+               goto out;
+
+       spin_lock(&template_list);
+       list_add_tail_rcu(&template_desc->list, &defined_templates);
+       spin_unlock(&template_list);
+out:
+       return template_desc;
+}
+
+static int ima_restore_template_data(struct ima_template_desc *template_desc,
+                                    void *template_data,
+                                    int template_data_size,
+                                    struct ima_template_entry **entry)
+{
+       struct binary_field_data {
+               u32 len;
+               u8 data[0];
+       } __packed;
+
+       struct binary_field_data *field_data;
+       int offset = 0;
+       int ret = 0;
+       int i;
+
+       *entry = kzalloc(sizeof(**entry) +
+                   template_desc->num_fields * sizeof(struct ima_field_data),
+                   GFP_NOFS);
+       if (!*entry)
+               return -ENOMEM;
+
+       (*entry)->template_desc = template_desc;
+       for (i = 0; i < template_desc->num_fields; i++) {
+               field_data = template_data + offset;
+
+               /* Each field of the template data is prefixed with a length. */
+               if (offset > (template_data_size - sizeof(*field_data))) {
+                       pr_err("Restoring the template field failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               offset += sizeof(*field_data);
+
+               if (ima_canonical_fmt)
+                       field_data->len = le32_to_cpu(field_data->len);
+
+               if (offset > (template_data_size - field_data->len)) {
+                       pr_err("Restoring the template field data failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               offset += field_data->len;
+
+               (*entry)->template_data[i].len = field_data->len;
+               (*entry)->template_data_len += sizeof(field_data->len);
+
+               (*entry)->template_data[i].data =
+                       kzalloc(field_data->len + 1, GFP_KERNEL);
+               if (!(*entry)->template_data[i].data) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               memcpy((*entry)->template_data[i].data, field_data->data,
+                       field_data->len);
+               (*entry)->template_data_len += field_data->len;
+       }
+
+       if (ret < 0) {
+               ima_free_template_entry(*entry);
+               *entry = NULL;
+       }
+
+       return ret;
+}
+
+/* Restore the serialized binary measurement list without extending PCRs. */
+int ima_restore_measurement_list(loff_t size, void *buf)
+{
+       struct binary_hdr_v1 {
+               u32 pcr;
+               u8 digest[TPM_DIGEST_SIZE];
+               u32 template_name_len;
+               char template_name[0];
+       } __packed;
+       char template_name[MAX_TEMPLATE_NAME_LEN];
+
+       struct binary_data_v1 {
+               u32 template_data_size;
+               char template_data[0];
+       } __packed;
+
+       struct ima_kexec_hdr *khdr = buf;
+       struct binary_hdr_v1 *hdr_v1;
+       struct binary_data_v1 *data_v1;
+
+       void *bufp = buf + sizeof(*khdr);
+       void *bufendp;
+       struct ima_template_entry *entry;
+       struct ima_template_desc *template_desc;
+       unsigned long count = 0;
+       int ret = 0;
+
+       if (!buf || size < sizeof(*khdr))
+               return 0;
+
+       if (ima_canonical_fmt) {
+               khdr->version = le16_to_cpu(khdr->version);
+               khdr->count = le64_to_cpu(khdr->count);
+               khdr->buffer_size = le64_to_cpu(khdr->buffer_size);
+       }
+
+       if (khdr->version != 1) {
+               pr_err("attempting to restore a incompatible measurement list");
+               return -EINVAL;
+       }
+
+       if (khdr->count > ULONG_MAX - 1) {
+               pr_err("attempting to restore too many measurements");
+               return -EINVAL;
+       }
+
+       /*
+        * ima kexec buffer prefix: version, buffer size, count
+        * v1 format: pcr, digest, template-name-len, template-name,
+        *            template-data-size, template-data
+        */
+       bufendp = buf + khdr->buffer_size;
+       while ((bufp < bufendp) && (count++ < khdr->count)) {
+               hdr_v1 = bufp;
+               if (bufp > (bufendp - sizeof(*hdr_v1))) {
+                       pr_err("attempting to restore partial measurement\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               bufp += sizeof(*hdr_v1);
+
+               if (ima_canonical_fmt)
+                       hdr_v1->template_name_len =
+                           le32_to_cpu(hdr_v1->template_name_len);
+
+               if ((hdr_v1->template_name_len >= MAX_TEMPLATE_NAME_LEN) ||
+                   (bufp > (bufendp - hdr_v1->template_name_len))) {
+                       pr_err("attempting to restore a template name \
+                               that is too long\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               data_v1 = bufp += (u_int8_t)hdr_v1->template_name_len;
+
+               /* template name is not null terminated */
+               memcpy(template_name, hdr_v1->template_name,
+                      hdr_v1->template_name_len);
+               template_name[hdr_v1->template_name_len] = 0;
+
+               if (strcmp(template_name, "ima") == 0) {
+                       pr_err("attempting to restore an unsupported \
+                               template \"%s\" failed\n", template_name);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               template_desc = lookup_template_desc(template_name);
+               if (!template_desc) {
+                       template_desc = restore_template_fmt(template_name);
+                       if (!template_desc)
+                               break;
+               }
+
+               /*
+                * Only the running system's template format is initialized
+                * on boot.  As needed, initialize the other template formats.
+                */
+               ret = template_desc_init_fields(template_desc->fmt,
+                                               &(template_desc->fields),
+                                               &(template_desc->num_fields));
+               if (ret < 0) {
+                       pr_err("attempting to restore the template fmt \"%s\" \
+                               failed\n", template_desc->fmt);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (bufp > (bufendp - sizeof(data_v1->template_data_size))) {
+                       pr_err("restoring the template data size failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               bufp += (u_int8_t) sizeof(data_v1->template_data_size);
+
+               if (ima_canonical_fmt)
+                       data_v1->template_data_size =
+                           le32_to_cpu(data_v1->template_data_size);
+
+               if (bufp > (bufendp - data_v1->template_data_size)) {
+                       pr_err("restoring the template data failed\n");
+                       ret = -EINVAL;
+                       break;
+               }
+               bufp += data_v1->template_data_size;
+
+               ret = ima_restore_template_data(template_desc,
+                                               data_v1->template_data,
+                                               data_v1->template_data_size,
+                                               &entry);
+               if (ret < 0)
+                       break;
+
+               memcpy(entry->digest, hdr_v1->digest, TPM_DIGEST_SIZE);
+               entry->pcr =
+                   !ima_canonical_fmt ? hdr_v1->pcr : le32_to_cpu(hdr_v1->pcr);
+               ret = ima_restore_measurement_entry(entry);
+               if (ret < 0)
+                       break;
+
+       }
+       return ret;
+}
index f9bae04ba1762cd3e91728e4506719739b541e7d..f9ba37b3928dce36bb940e7aa4620848aca1f15b 100644 (file)
@@ -103,8 +103,11 @@ static void ima_show_template_data_binary(struct seq_file *m,
        u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ?
            strlen(field_data->data) : field_data->len;
 
-       if (show != IMA_SHOW_BINARY_NO_FIELD_LEN)
-               ima_putc(m, &len, sizeof(len));
+       if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) {
+               u32 field_len = !ima_canonical_fmt ? len : cpu_to_le32(len);
+
+               ima_putc(m, &field_len, sizeof(field_len));
+       }
 
        if (!len)
                return;
index 71620fa959530211c6c73c25ab71aaaba7cfa50a..45be8b55a663453748a8c3156b865610fcfc37a8 100644 (file)
@@ -125,12 +125,13 @@ struct nfit_test_dcr {
        (((node & 0xfff) << 16) | ((socket & 0xf) << 12) \
         | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf))
 
-static u32 handle[NUM_DCR] = {
+static u32 handle[] = {
        [0] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 0),
        [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),
        [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),
        [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
        [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
+       [5] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0),
 };
 
 static unsigned long dimm_fail_cmd_flags[NUM_DCR];
@@ -142,6 +143,7 @@ struct nfit_test {
        void *nfit_buf;
        dma_addr_t nfit_dma;
        size_t nfit_size;
+       int dcr_idx;
        int num_dcr;
        int num_pm;
        void **dimm;
@@ -426,11 +428,11 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
                        break;
                case ND_CMD_GET_CONFIG_DATA:
                        rc = nfit_test_cmd_get_config_data(buf, buf_len,
-                               t->label[i]);
+                               t->label[i - t->dcr_idx]);
                        break;
                case ND_CMD_SET_CONFIG_DATA:
                        rc = nfit_test_cmd_set_config_data(buf, buf_len,
-                               t->label[i]);
+                               t->label[i - t->dcr_idx]);
                        break;
                case ND_CMD_SMART:
                        rc = nfit_test_cmd_smart(buf, buf_len);
@@ -682,7 +684,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
        if (!t->spa_set[2])
                return -ENOMEM;
 
-       for (i = 0; i < NUM_DCR; i++) {
+       for (i = 0; i < t->num_dcr; i++) {
                t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]);
                if (!t->dimm[i])
                        return -ENOMEM;
@@ -699,7 +701,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        return -ENOMEM;
        }
 
-       for (i = 0; i < NUM_DCR; i++) {
+       for (i = 0; i < t->num_dcr; i++) {
                t->dcr[i] = test_alloc(t, LABEL_SIZE, &t->dcr_dma[i]);
                if (!t->dcr[i])
                        return -ENOMEM;
@@ -728,6 +730,7 @@ static int nfit_test1_alloc(struct nfit_test *t)
        size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2
                + sizeof(struct acpi_nfit_memory_map)
                + offsetof(struct acpi_nfit_control_region, window_size);
+       int i;
 
        t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma);
        if (!t->nfit_buf)
@@ -738,6 +741,13 @@ static int nfit_test1_alloc(struct nfit_test *t)
        if (!t->spa_set[0])
                return -ENOMEM;
 
+       for (i = 0; i < t->num_dcr; i++) {
+               t->label[i] = test_alloc(t, LABEL_SIZE, &t->label_dma[i]);
+               if (!t->label[i])
+                       return -ENOMEM;
+               sprintf(t->label[i], "label%d", i);
+       }
+
        t->spa_set[1] = test_alloc(t, SPA_VCD_SIZE, &t->spa_set_dma[1]);
        if (!t->spa_set[1])
                return -ENOMEM;
@@ -1450,7 +1460,7 @@ static void nfit_test1_setup(struct nfit_test *t)
        memdev = nfit_buf + offset;
        memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
        memdev->header.length = sizeof(*memdev);
-       memdev->device_handle = 0;
+       memdev->device_handle = handle[5];
        memdev->physical_id = 0;
        memdev->region_id = 0;
        memdev->range_index = 0+1;
@@ -1472,7 +1482,7 @@ static void nfit_test1_setup(struct nfit_test *t)
                        window_size);
        dcr->region_index = 0+1;
        dcr_common_init(dcr);
-       dcr->serial_number = ~0;
+       dcr->serial_number = ~handle[5];
        dcr->code = NFIT_FIC_BYTE;
        dcr->windows = 0;
 
@@ -1483,6 +1493,9 @@ static void nfit_test1_setup(struct nfit_test *t)
        set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en);
        set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en);
        set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en);
+       set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en);
+       set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en);
+       set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en);
 }
 
 static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
@@ -1886,12 +1899,15 @@ static __init int nfit_test_init(void)
                switch (i) {
                case 0:
                        nfit_test->num_pm = NUM_PM;
+                       nfit_test->dcr_idx = 0;
                        nfit_test->num_dcr = NUM_DCR;
                        nfit_test->alloc = nfit_test0_alloc;
                        nfit_test->setup = nfit_test0_setup;
                        break;
                case 1:
                        nfit_test->num_pm = 1;
+                       nfit_test->dcr_idx = NUM_DCR;
+                       nfit_test->num_dcr = 1;
                        nfit_test->alloc = nfit_test1_alloc;
                        nfit_test->setup = nfit_test1_setup;
                        break;