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");