diff --git a/arch/powerpc/boot/dts/powerpc-quanta-ly6-p2020-r0.dts b/arch/powerpc/boot/dts/powerpc-quanta-ly6-p2020-r0.dts
new file mode 100644
index 00000000..da100ab1
--- /dev/null
+++ b/arch/powerpc/boot/dts/powerpc-quanta-ly6-p2020-r0.dts
@@ -0,0 +1,1238 @@
+/*
+ *
+ *
+ * Copyright 2013, 2014 BigSwitch Networks, Inc.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms ofthe GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ *
+ *
+ *
+ *
+ * Device tree for the Quanta LY6 P2020.
+ *
+ */
+
+
+/dts-v1/;
+
+/ {
+ model = "powerpc-quanta-ly6-p2020-r0";
+ compatible = "fsl,P2020RDB";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ ethernet0 = &enet1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ pci2 = &pci2;
+ mpic-msgr-block0 = &mpic_msgr_block0;
+ mpic-msgr-block1 = &mpic_msgr_block1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,P2020@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ next-level-cache = <&l2>;
+ };
+
+ PowerPC,P2020@1 {
+ device_type = "cpu";
+ reg = <0x1>;
+ next-level-cache = <&l2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ localbus@ffe05000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus";
+ reg = <0 0xffe05000 0 0x1000>;
+ interrupts = <19 2>;
+ interrupt-parent = <&mpic>;
+
+ ranges = <0x0 0x0 0x0 0xec000000 0x4000000
+ 0x1 0x0 0x0 0xe8000000 0x4000000>;
+
+ flash@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x4000000>;
+ bank-width = <2>;
+
+ /*
+ * ONIE flash layout (reverse-engineered:
+ * - one ~64MiB loader partition
+ * - 4 MiB onie partition
+ * - uboot-env and uboot
+ * - 64MiB leftover space for jffs2
+ *
+ */
+
+ flash@0 {
+ label = "onl-loader";
+ reg = <0x00000000 0x03b60000>;
+ };
+
+ flash@1 {
+ label = "onie";
+ reg = <0x01b60000 0x00400000>;
+ read-only;
+ };
+
+ flash@2 {
+ label = "uboot-env";
+ reg = <0x01f60000 0x00020000>;
+ };
+
+ flash@3 {
+ label = "uboot";
+ reg = <0x01f80000 0x00080000>;
+ read-only;
+ };
+
+ };
+
+ flash@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x1 0x0 0x4000000>;
+ bank-width = <2>;
+
+ flash@4 {
+ label = "mnt-flash";
+ reg = <0x00000000 0x04000000>;
+ };
+ };
+ };
+
+ soc@ffe00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "fsl,p2020-immr", "simple-bus";
+ ranges = <0x0 0x0 0xffe00000 0x100000>;
+ bus-frequency = <0>;
+
+ ecm-law@0 {
+ compatible = "fsl,ecm-law";
+ reg = <0x0 0x1000>;
+ fsl,num-laws = <12>;
+ };
+
+ ecm@1000 {
+ compatible = "fsl,p2020-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <17 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,p2020-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <18 2>;
+ };
+
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+
+ dimm@51 {
+ compatible = "at,spd";
+ reg = <0x52>;
+ read-only;
+ };
+
+ rtc@68 {
+ compatible = "dallas,ds1339";
+ reg = <0x68>;
+ };
+
+ mux-cb@71 {
+ compatible = "nxp,pca9546";
+ reg = <0x71>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ gpio-cb-9555@20 {
+ compatible = "nxp,pca9555";
+ reg = <0x20>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ eeprom-cb@53 {
+ compatible = "at,24c02";
+ reg = <0x53>;
+ read-only;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ gpio-cb-9554@21 {
+ compatible = "nxp,pca9554";
+ reg = <0x21>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+ };
+
+ temp-fan@4e {
+ compatible = "quanta_ly6_hwmon";
+ reg = <0x4e>;
+ };
+
+ mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ mux@73 {
+ compatible = "nxp,pca9548";
+ reg = <0x73>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ qsfp-eeprom-1@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-1@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ qsfp-eeprom-2@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-2@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ qsfp-eeprom-3@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-3@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ qsfp-eeprom-4@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-4@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ qsfp-eeprom-5@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-5@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+
+ qsfp-eeprom-6@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-6@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ qsfp-eeprom-7@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-7@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ qsfp-eeprom-8@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-8@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ mux@74 {
+ compatible = "nxp,pca9548";
+ reg = <0x74>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ qsfp-eeprom-9@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-9@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ qsfp-eeprom-10@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-10@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ qsfp-eeprom-11@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-11@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ qsfp-eeprom-12@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-12@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ qsfp-eeprom-13@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-13@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+
+ qsfp-eeprom-14@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-14@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ qsfp-eeprom-15@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-15@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ qsfp-eeprom-16@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-16@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ mux@75 {
+ compatible = "nxp,pca9548";
+ reg = <0x75>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ qsfp-eeprom-17@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-17@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ qsfp-eeprom-18@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-18@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ qsfp-eeprom-19@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-19@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ qsfp-eeprom-20@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-20@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ qsfp-eeprom-21@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-21@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+
+ qsfp-eeprom-22@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-22@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ qsfp-eeprom-23@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-23@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ qsfp-eeprom-24@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-24@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ mux@76 {
+ compatible = "nxp,pca9548";
+ reg = <0x76>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ qsfp-eeprom-25@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-25@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ qsfp-eeprom-26@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-26@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ qsfp-eeprom-27@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-27@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ qsfp-eeprom-28@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-28@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ qsfp-eeprom-29@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-29@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+
+ qsfp-eeprom-30@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-30@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ qsfp-eeprom-31@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-31@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+
+ i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ qsfp-eeprom-32@50 {
+ compatible = "at,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+ qsfp-eeprom-32@51 {
+ compatible = "at,24c02";
+ reg = <0x51>;
+ read-only;
+ };
+ };
+ };
+ };
+
+ i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ mux-cpld-2@3a {
+ compatible = "quanta_ly6_i2c_mux";
+ reg = <0x3a>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+
+ mux-cpld-3@3b {
+ compatible = "quanta_ly6_i2c_mux";
+ reg = <0x3b>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ gpio-1@24 {
+ compatible = "nxp,pca9555";
+ reg = <0x24>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+
+ i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ gpio-2@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+ };
+
+ mux@72 {
+ compatible = "nxp,pca9546";
+ reg = <0x72>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ psu-1@58 {
+ compatible = "pmbus";
+ reg = <0x58>;
+ };
+
+ psu-1@69 {
+ compatible = "pmbus";
+ reg = <0x69>;
+ };
+ };
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ psu-2@59 {
+ compatible = "pmbus";
+ reg = <0x59>;
+ };
+
+ psu-2@6f {
+ compatible = "pmbus";
+ reg = <0x6f>;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ gpio-psu-1@26 {
+ compatible = "nxp,pca9555";
+ reg = <0x26>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ eeprom-mb@54 {
+ compatible = "at,24c02";
+ reg = <0x54>;
+ read-only;
+ };
+ };
+ };
+ };
+
+ i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ dma@c300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,eloplus-dma";
+ reg = <0xc300 0x4>;
+ ranges = <0x0 0xc100 0x200>;
+ cell-index = <1>;
+ dma-channel@0 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <76 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <77 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <78 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <79 2>;
+ };
+ };
+
+ gpio: gpio-controller@f000 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8572-gpio";
+ reg = <0xf000 0x100>;
+ interrupts = <47 0x2>;
+ interrupt-parent = <&mpic>;
+ gpio-controller;
+ };
+
+ l2: l2-cache-controller@20000 {
+ compatible = "fsl,p2020-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x80000>; // L2,512K
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ };
+
+ dma@21300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,eloplus-dma";
+ reg = <0x21300 0x4>;
+ ranges = <0x0 0x21100 0x200>;
+ cell-index = <0>;
+ dma-channel@0 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ usb@22000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-usb2-dr";
+ reg = <0x22000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <28 0x2>;
+ phy_type = "ulpi";
+ dr_mode = "host";
+ };
+
+ ptp_timer: ptimer@24e00 {
+ compatible = "fsl,gianfar-ptp-timer";
+ reg = <0x24e00 0xb0>;
+ };
+
+ enet1: ethernet@25000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <1>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x25000 0x1000>;
+ ranges = <0x0 0x25000 0x1000>;
+ local-mac-address = [ 00 c0 9f 01 02 03 ];
+ interrupts = <35 2 36 2 40 2>;
+ interrupt-parent = <&mpic>;
+ phy-connection-type = "sgmii";
+ phy-handle = <&phy0>;
+ tbi-handle = <&tbi0>;
+ };
+
+ mdio@24520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x24520 0x20>;
+ phy0: ethernet-phy@0 {
+ reg = <0x5>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ mdio@25520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x25520 0x20>;
+
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ sdhci@2e000 {
+ compatible = "fsl,p2020-esdhc", "fsl,esdhc";
+ reg = <0x2e000 0x1000>;
+ interrupts = <72 0x2>;
+ interrupt-parent = <&mpic>;
+ clock-frequency = <0>;
+ };
+
+ crypto@30000 {
+ compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4",
+ "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
+ reg = <0x30000 0x10000>;
+ interrupts = <45 2 58 2>;
+ interrupt-parent = <&mpic>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0xbfe>;
+ fsl,descriptor-types-mask = <0x3ab0ebf>;
+ fsl,multi-host-mode = "dual";
+ fsl,channel-remap = <0x3>;
+ };
+
+ mpic: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x40000 0x40000>;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ };
+
+ mpic_msgr_block0: message@41400 {
+ compatible = "fsl,mpic-v3.1-msgr";
+ reg = <0x41400 0x200>;
+ interrupts = <
+ 0xb0 2
+ 0xb1 2
+ 0xb2 2
+ 0xb3 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ mpic_msgr_block1: message@42400 {
+ compatible = "fsl,mpic-v3.1-msgr";
+ reg = <0x42400 0x200>;
+ interrupts = <
+ 0xb4 2
+ 0xb5 2
+ 0xb6 2
+ 0xb7 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ msi@41600 {
+ compatible = "fsl,p2020-msi", "fsl,mpic-msi";
+ reg = <0x41600 0x80>;
+ msi-available-ranges = <0 0x100>;
+ interrupts = <
+ 0xe0 0
+ 0xe1 0
+ 0xe2 0
+ 0xe3 0
+ 0xe4 0
+ 0xe5 0
+ 0xe6 0
+ 0xe7 0>;
+ interrupt-parent = <&mpic>;
+ };
+
+ global-utilities@e0000 {
+ compatible = "fsl,p2020-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+ };
+
+ pci2: pcie@ffe0a000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe0a000 0 0x1000>;
+ bus-range = <0 255>;
+ ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+ clock-frequency = <100000000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <26 2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x3 0x1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xc0000000
+ 0x2000000 0x0 0xc0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x10000>;
+ };
+ };
+};
diff --git a/arch/powerpc/configs/85xx/onl_mpc85xx_defconfig b/arch/powerpc/configs/85xx/onl_mpc85xx_defconfig
index 1fc0e957..580e04a2 100644
--- a/arch/powerpc/configs/85xx/onl_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/onl_mpc85xx_defconfig
@@ -1180,6 +1180,7 @@ CONFIG_I2C_MUX=y
# CONFIG_I2C_MUX_PCA9541 is not set
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_MUX_QUANTA_LY2=y
+CONFIG_I2C_MUX_QUANTA_LY6=y
CONFIG_I2C_MUX_QUANTA_LY5=y
CONFIG_I2C_HELPER_AUTO=y
@@ -1459,6 +1460,7 @@ CONFIG_SENSORS_EMC2305=y
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83L786NG is not set
CONFIG_SENSORS_QUANTA_LY_HWMON=y
+CONFIG_SENSORS_QUANTA_LY6_HWMON=y
# CONFIG_THERMAL is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_CORE=y
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index ede8771d..027398da 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -43,7 +43,6 @@
#define DBG(fmt, args...)
#endif
-
void __init mpc85xx_rdb_pic_init(void)
{
struct mpic *mpic;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 9d5a0ddd..b66c37a2 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1489,6 +1489,13 @@ config SENSORS_QUANTA_LY_HWMON
If you say yes here you get support for the Quanta LYx hardware
monitor.
+config SENSORS_QUANTA_LY6_HWMON
+ tristate "Quanta LY6 hardware monitor"
+ depends on I2C
+ help
+ If you say yes here you get support for the Quanta LY6 hardware
+ monitor.
+
if ACPI
comment "ACPI drivers"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 956c9051..d0aa793e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -137,6 +137,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_QUANTA_LY_HWMON) += quanta-ly-hwmon.o
+obj-$(CONFIG_SENSORS_QUANTA_LY6_HWMON) += quanta-ly6-hwmon.o
obj-$(CONFIG_PMBUS) += pmbus/
diff --git a/drivers/hwmon/quanta-ly6-hwmon.c b/drivers/hwmon/quanta-ly6-hwmon.c
new file mode 100644
index 00000000..e03079cd
--- /dev/null
+++ b/drivers/hwmon/quanta-ly6-hwmon.c
@@ -0,0 +1,217 @@
+/*
+ *
+ *
+ * Copyright 2013, 2014 BigSwitch Networks, Inc.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms ofthe GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ *
+ *
+ *
+ * A hwmon driver for the Quanta LY6
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static const unsigned short normal_i2c[] = { 0x4E, I2C_CLIENT_END };
+
+#define QUANTA_LY6_HWMON_REG_TEMP_INPUT_BASE 0x20
+#define QUANTA_LY6_HWMON_REG_FAN_MODE 0x33
+#define QUANTA_LY6_HWMON_REG_FAN_DIR 0x56
+#define QUANTA_LY6_HWMON_REG_FAN_PWM_BASE 0x3C
+#define QUANTA_LY6_HWMON_REG_FAN_INPUT_BASE 0x40
+
+#define QUANTA_LY6_HWMON_FAN_MANUAL_MODE 1
+#define QUANTA_LY6_HWMON_FAN_SMART_MODE 3
+
+#define QUANTA_LY6_HWMON_NUM_FANS 6
+
+struct quanta_ly6_hwmon_data {
+ struct device *hwmon_dev;
+ struct attribute_group attrs;
+ struct mutex lock;
+};
+
+static int quanta_ly6_hwmon_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int quanta_ly6_hwmon_remove(struct i2c_client *client);
+
+static const struct i2c_device_id quanta_ly6_hwmon_id[] = {
+ { "quanta_ly6_hwmon", 0xf600 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, quanta_ly6_hwmon_id);
+
+static struct i2c_driver quanta_ly6_hwmon_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "quanta_ly6_hwmon",
+ },
+ .probe = quanta_ly6_hwmon_probe,
+ .remove = quanta_ly6_hwmon_remove,
+ .id_table = quanta_ly6_hwmon_id,
+ .address_list = normal_i2c,
+};
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct quanta_ly6_hwmon_data *data = i2c_get_clientdata(client);
+ int temp;
+
+ mutex_lock(&data->lock);
+ temp = i2c_smbus_read_byte_data(client,
+ QUANTA_LY6_HWMON_REG_TEMP_INPUT_BASE
+ + attr->index);
+ mutex_unlock(&data->lock);
+ return sprintf(buf, "%d\n", 1000 * temp);
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct quanta_ly6_hwmon_data *data = i2c_get_clientdata(client);
+ int fan;
+
+ mutex_lock(&data->lock);
+ fan = i2c_smbus_read_word_swapped(client,
+ QUANTA_LY6_HWMON_REG_FAN_INPUT_BASE
+ + 2 * attr->index);
+ mutex_unlock(&data->lock);
+ return sprintf(buf, "%d\n", fan);
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct quanta_ly6_hwmon_data *data = i2c_get_clientdata(client);
+ int pwm;
+
+ mutex_lock(&data->lock);
+ pwm = i2c_smbus_read_word_swapped(client,
+ QUANTA_LY6_HWMON_REG_FAN_PWM_BASE
+ + 2 * attr->index);
+ mutex_unlock(&data->lock);
+ return sprintf(buf, "%d\n", pwm * 255 / 10000);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct quanta_ly6_hwmon_data *data = i2c_get_clientdata(client);
+ long val;
+ int ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret)
+ return ret;
+ mutex_lock(&data->lock);
+ i2c_smbus_write_word_swapped(client,
+ QUANTA_LY6_HWMON_REG_FAN_PWM_BASE
+ + 2 * attr->index, val * 10000 / 255);
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+
+static struct attribute *quanta_ly6_hwmon_attr[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ NULL
+};
+
+static int quanta_ly6_hwmon_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct quanta_ly6_hwmon_data *data;
+ int err;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct quanta_ly6_hwmon_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->lock);
+
+ dev_info(&client->dev, "%s chip found\n", client->name);
+
+ data->attrs.attrs = quanta_ly6_hwmon_attr;
+ err = sysfs_create_group(&client->dev.kobj, &data->attrs);
+ if (err)
+ return err;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ i2c_smbus_write_byte_data(client,
+ QUANTA_LY6_HWMON_REG_FAN_MODE,
+ QUANTA_LY6_HWMON_FAN_SMART_MODE);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+ return err;
+}
+
+static int quanta_ly6_hwmon_remove(struct i2c_client *client)
+{
+ struct quanta_ly6_hwmon_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+ return 0;
+}
+
+module_i2c_driver(quanta_ly6_hwmon_driver);
+
+MODULE_AUTHOR("QCT Technical ");
+MODULE_DESCRIPTION("Quanta LY6 hardware monitor driver");
+MODULE_LICENSE("LGPL");
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index c70f50a3..4131fdc7 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -53,6 +53,12 @@ config I2C_MUX_QUANTA_LY2
If you say yes here you get support for the Quanta LY2 I2C/GPIO
multiplexer.
+config I2C_MUX_QUANTA_LY6
+ tristate "Quanta LY6 I2C multiplexer"
+ help
+ If you say yes here you get support for the Quanta LY6 I2C/GPIO
+ multiplexer.
+
config I2C_MUX_QUANTA_LY5
tristate "Quanta LY5 I2C multiplexer"
help
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index af05ecab..f9658fde 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
obj-$(CONFIG_I2C_MUX_QUANTA_LY2) += quanta-ly2-i2c-mux.o
+obj-$(CONFIG_I2C_MUX_QUANTA_LY6) += quanta-ly6-i2c-mux.o
obj-$(CONFIG_I2C_MUX_QUANTA_LY5) += quanta-ly5-i2c-mux.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/muxes/quanta-ly6-i2c-mux.c b/drivers/i2c/muxes/quanta-ly6-i2c-mux.c
new file mode 100644
index 00000000..a71733a6
--- /dev/null
+++ b/drivers/i2c/muxes/quanta-ly6-i2c-mux.c
@@ -0,0 +1,285 @@
+/*
+ *
+ *
+ * Copyright 2013, 2014 BigSwitch Networks, Inc.
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms ofthe GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ *
+ *
+ *
+ * An I2C multiplexer driver for the Quanta LY6
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * Disable QSFP module reset (n=1..16)
+ * RST_N_Px1 INTL_Px1 MOD_ASB_Px1 LPMODE_Px1 RST_N_Px2 INTL_Px2 MOD_ASB_Px2 LPMODE_Px2
+ * 7 6 5 4 3 2 1 0
+ * port 2(n-1)+1 2(n-1)+1 2(n-1)+1 2(n-1)+1 2(n-1) 2(n-1) 2(n-1) 2(n-1)
+ */
+#define QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS 32
+#define QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS 32
+#define QUANTA_LY6_I2C_MUX_NUM_GPIO_GROUPS 4
+#define QUANTA_LY6_I2C_MUX_NUM_GPIOS (QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS + QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS)
+#define QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP (QUANTA_LY6_I2C_MUX_NUM_GPIOS / QUANTA_LY6_I2C_MUX_NUM_GPIO_GROUPS)
+
+struct quanta_ly6_i2c_mux {
+ struct i2c_client *client;
+ struct gpio_chip gpio_chip;
+ u16 gpio_write_val;
+};
+
+static const struct i2c_device_id quanta_ly6_i2c_mux_id[] = {
+ {"quanta_ly6_i2c_mux", 0xf600},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, quanta_ly6_i2c_mux_id);
+
+/*
+ * Read 2 bytes once per command, and command should be group 1~4
+ */
+static int quanta_ly6_i2c_mux_reg_read(struct i2c_adapter *adap,
+ struct i2c_client *client,
+ u8 command, u16 *val)
+{
+ int ret = -ENODEV;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg[2];
+ char buf[4];
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ buf[0] = command;
+ msg[0].buf = &buf[0];
+
+ /* always receive 3 bytes, else the PLD freaks out */
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 3;
+ msg[1].buf = &buf[1];
+
+ ret = adap->algo->master_xfer(adap, msg, 2);
+ if (val != NULL && ret > -1)
+ *val = ((buf[2] << 8) | buf[1]);
+ } else {
+ union i2c_smbus_data data;
+ data.block[0] = 3; /* block transfer length */
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_READ,
+ command,
+ I2C_SMBUS_I2C_BLOCK_DATA, &data);
+ if (val != NULL)
+ *val = ((data.block[2] << 8) | data.block[1]);
+ }
+
+ return ret;
+}
+
+/*
+ * Write 3 bytes once per command, and command should be group 1~4
+ */
+static int quanta_ly6_i2c_mux_reg_write(struct i2c_adapter *adap,
+ struct i2c_client *client,
+ u8 command, u16 val)
+{
+ int ret = -ENODEV;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg;
+ char buf[4];
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 3;
+ buf[0] = command;
+ buf[1] = (val & 0xff);
+ buf[2] = ((val >> 8) & 0xff);
+ buf[3] = 0;
+ msg.buf = buf;
+ ret = adap->algo->master_xfer(adap, &msg, 1);
+ } else {
+ union i2c_smbus_data data;
+
+ data.block[0] = 3;
+ data.block[1] = (val & 0xff);
+ data.block[2] = ((val >> 8) & 0xff);
+ data.block[3] = 0;
+
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags,
+ I2C_SMBUS_WRITE,
+ command,
+ I2C_SMBUS_I2C_BLOCK_DATA, &data);
+ }
+
+ return ret;
+}
+
+static void quanta_ly6_i2c_mux_gpio_set(struct gpio_chip *gc, unsigned offset,
+ int val)
+{
+ struct quanta_ly6_i2c_mux *data = container_of(
+ gc, struct quanta_ly6_i2c_mux, gpio_chip);
+ int ret;
+ u32 group;
+
+ /* ignore write attempts to input GPIOs */
+ if ((offset % 4) == 1 || (offset % 4) == 2) {
+ dev_warn(&data->client->dev,
+ "ignoring GPIO write for input for pin %d\n",
+ offset);
+ return;
+ }
+
+ group = (offset / QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP) + 1;
+ ret = quanta_ly6_i2c_mux_reg_read(data->client->adapter,
+ data->client,
+ group,
+ &data->gpio_write_val);
+
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "quanta_ly6_i2c_mux_reg_read failed\n");
+ return;
+ }
+
+ if (val)
+ data->gpio_write_val |= (1 << (offset % QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP));
+ else
+ data->gpio_write_val &= ~(1 << (offset % QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP));
+
+ quanta_ly6_i2c_mux_reg_write(
+ data->client->adapter, data->client,
+ group,
+ data->gpio_write_val);
+}
+
+static int quanta_ly6_i2c_mux_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ int ret;
+ u16 buf;
+ u32 group;
+ struct quanta_ly6_i2c_mux *data = container_of(
+ gc, struct quanta_ly6_i2c_mux, gpio_chip);
+
+ if (offset >= (QUANTA_LY6_I2C_MUX_NUM_GPIOS)) {
+ offset -= (QUANTA_LY6_I2C_MUX_NUM_GPIOS);
+ }
+
+ group = (offset / QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP) + 1;
+ buf = 0;
+ ret = quanta_ly6_i2c_mux_reg_read(data->client->adapter,
+ data->client,
+ group,
+ &buf);
+
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "quanta_ly6_i2c_mux_reg_read failed\n");
+ return 0;
+ }
+ return (buf & (1 << (offset % QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP))) ? 1 : 0;
+}
+
+static struct gpio_chip quanta_ly6_i2c_mux_gpio_chip = {
+ .label = "quanta_ly6_i2c_mux_gpio_chip",
+ .owner = THIS_MODULE,
+ .ngpio = QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS + QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS,
+ .base = -1,
+ .set = quanta_ly6_i2c_mux_gpio_set,
+ .get = quanta_ly6_i2c_mux_gpio_get,
+};
+
+static int quanta_ly6_i2c_mux_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct quanta_ly6_i2c_mux *data;
+ int ret = -ENODEV;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto err;
+
+ data = kzalloc(sizeof(struct quanta_ly6_i2c_mux), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+
+ if (i2c_smbus_write_byte(client, 0) < 0) {
+ dev_warn(&client->dev, "probe failed\n");
+ goto exit_free;
+ }
+
+ data->gpio_chip = quanta_ly6_i2c_mux_gpio_chip;
+ data->gpio_chip.dev = &client->dev;
+ data->gpio_write_val = 0xff;
+
+ ret = gpiochip_add(&data->gpio_chip);
+ if (ret) {
+ dev_err(&client->dev, "failed to register GPIOs\n");
+ goto exit_free;
+ }
+
+ dev_info(&client->dev,
+ "registered GPIOs for I2C mux %s (%d read, %d write)\n",
+ client->name,
+ QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS,
+ QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS);
+
+ return 0;
+
+exit_free:
+ kfree(data);
+err:
+ return ret;
+}
+
+static int quanta_ly6_i2c_mux_remove(struct i2c_client *client)
+{
+ struct quanta_ly6_i2c_mux *data = i2c_get_clientdata(client);
+ int ret;
+
+ ret = gpiochip_remove(&data->gpio_chip);
+ if (ret)
+ return ret;
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver quanta_ly6_i2c_mux_driver = {
+ .driver = {
+ .name = "quanta_ly6_i2c_mux",
+ .owner = THIS_MODULE,
+ },
+ .probe = quanta_ly6_i2c_mux_probe,
+ .remove = quanta_ly6_i2c_mux_remove,
+ .id_table = quanta_ly6_i2c_mux_id,
+};
+
+module_i2c_driver(quanta_ly6_i2c_mux_driver);
+
+MODULE_AUTHOR("QCT Technical ");
+MODULE_DESCRIPTION("Quanta LY6 I2C multiplexer driver");
+MODULE_LICENSE("LGPL");