code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2011 - 2014 Xilinx
 */

/ {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "xlnx,zynq-7000";

	cpus {
		#address-cells = <1>;
		#size-cells = <0>;

		cpu0: cpu@0 {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <0>;
			clocks = <&clkc 3>;
			clock-latency = <1000>;
			cpu0-supply = <&regulator_vccpint>;
			operating-points = <
				/* kHz    uV */
				666667  1000000
				333334  1000000
			>;
		};

		cpu1: cpu@1 {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <1>;
			clocks = <&clkc 3>;
		};
	};

	fpga_full: fpga-full {
		compatible = "fpga-region";
		fpga-mgr = <&devcfg>;
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;
	};

	pmu@f8891000 {
		compatible = "arm,cortex-a9-pmu";
		interrupts = <0 5 4>, <0 6 4>;
		interrupt-parent = <&intc>;
		reg = <0xf8891000 0x1000>,
		      <0xf8893000 0x1000>;
	};

	regulator_vccpint: fixedregulator {
		compatible = "regulator-fixed";
		regulator-name = "VCCPINT";
		regulator-min-microvolt = <1000000>;
		regulator-max-microvolt = <1000000>;
		regulator-boot-on;
		regulator-always-on;
	};

	replicator {
		compatible = "arm,coresight-static-replicator";
		clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
		clock-names = "apb_pclk", "dbg_trc", "dbg_apb";

		out-ports {
			#address-cells = <1>;
			#size-cells = <0>;

			/* replicator output ports */
			port@0 {
				reg = <0>;
				replicator_out_port0: endpoint {
					remote-endpoint = <&tpiu_in_port>;
				};
			};
			port@1 {
				reg = <1>;
				replicator_out_port1: endpoint {
					remote-endpoint = <&etb_in_port>;
				};
			};
		};
		in-ports {
			/* replicator input port */
			port {
				replicator_in_port0: endpoint {
					remote-endpoint = <&funnel_out_port>;
				};
			};
		};
	};

	amba: axi {
		compatible = "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		interrupt-parent = <&intc>;
		ranges;

		adc: adc@f8007100 {
			compatible = "xlnx,zynq-xadc-1.00.a";
			reg = <0xf8007100 0x20>;
			interrupts = <0 7 4>;
			interrupt-parent = <&intc>;
			clocks = <&clkc 12>;
		};

		can0: can@e0008000 {
			compatible = "xlnx,zynq-can-1.0";
			status = "disabled";
			clocks = <&clkc 19>, <&clkc 36>;
			clock-names = "can_clk", "pclk";
			reg = <0xe0008000 0x1000>;
			interrupts = <0 28 4>;
			interrupt-parent = <&intc>;
			tx-fifo-depth = <0x40>;
			rx-fifo-depth = <0x40>;
		};

		can1: can@e0009000 {
			compatible = "xlnx,zynq-can-1.0";
			status = "disabled";
			clocks = <&clkc 20>, <&clkc 37>;
			clock-names = "can_clk", "pclk";
			reg = <0xe0009000 0x1000>;
			interrupts = <0 51 4>;
			interrupt-parent = <&intc>;
			tx-fifo-depth = <0x40>;
			rx-fifo-depth = <0x40>;
		};

		gpio0: gpio@e000a000 {
			compatible = "xlnx,zynq-gpio-1.0";
			#gpio-cells = <2>;
			clocks = <&clkc 42>;
			gpio-controller;
			interrupt-controller;
			#interrupt-cells = <2>;
			interrupt-parent = <&intc>;
			interrupts = <0 20 4>;
			reg = <0xe000a000 0x1000>;
		};

		i2c0: i2c@e0004000 {
			compatible = "cdns,i2c-r1p10";
			status = "disabled";
			clocks = <&clkc 38>;
			interrupt-parent = <&intc>;
			interrupts = <0 25 4>;
			reg = <0xe0004000 0x1000>;
			#address-cells = <1>;
			#size-cells = <0>;
		};

		i2c1: i2c@e0005000 {
			compatible = "cdns,i2c-r1p10";
			status = "disabled";
			clocks = <&clkc 39>;
			interrupt-parent = <&intc>;
			interrupts = <0 48 4>;
			reg = <0xe0005000 0x1000>;
			#address-cells = <1>;
			#size-cells = <0>;
		};

		intc: interrupt-controller@f8f01000 {
			compatible = "arm,cortex-a9-gic";
			#interrupt-cells = <3>;
			interrupt-controller;
			reg = <0xF8F01000 0x1000>,
			      <0xF8F00100 0x100>;
		};

		L2: cache-controller@f8f02000 {
			compatible = "arm,pl310-cache";
			reg = <0xF8F02000 0x1000>;
			interrupts = <0 2 4>;
			arm,data-latency = <3 2 2>;
			arm,tag-latency = <2 2 2>;
			cache-unified;
			cache-level = <2>;
		};

		mc: memory-controller@f8006000 {
			compatible = "xlnx,zynq-ddrc-a05";
			reg = <0xf8006000 0x1000>;
		};

		uart0: serial@e0000000 {
			compatible = "xlnx,xuartps", "cdns,uart-r1p8";
			status = "disabled";
			clocks = <&clkc 23>, <&clkc 40>;
			clock-names = "uart_clk", "pclk";
			reg = <0xE0000000 0x1000>;
			interrupts = <0 27 4>;
		};

		uart1: serial@e0001000 {
			compatible = "xlnx,xuartps", "cdns,uart-r1p8";
			status = "disabled";
			clocks = <&clkc 24>, <&clkc 41>;
			clock-names = "uart_clk", "pclk";
			reg = <0xE0001000 0x1000>;
			interrupts = <0 50 4>;
		};

		spi0: spi@e0006000 {
			compatible = "xlnx,zynq-spi-r1p6";
			reg = <0xe0006000 0x1000>;
			status = "disabled";
			interrupt-parent = <&intc>;
			interrupts = <0 26 4>;
			clocks = <&clkc 25>, <&clkc 34>;
			clock-names = "ref_clk", "pclk";
			#address-cells = <1>;
			#size-cells = <0>;
		};

		spi1: spi@e0007000 {
			compatible = "xlnx,zynq-spi-r1p6";
			reg = <0xe0007000 0x1000>;
			status = "disabled";
			interrupt-parent = <&intc>;
			interrupts = <0 49 4>;
			clocks = <&clkc 26>, <&clkc 35>;
			clock-names = "ref_clk", "pclk";
			#address-cells = <1>;
			#size-cells = <0>;
		};

		gem0: ethernet@e000b000 {
			compatible = "cdns,zynq-gem", "cdns,gem";
			reg = <0xe000b000 0x1000>;
			status = "disabled";
			interrupts = <0 22 4>;
			clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;
			clock-names = "pclk", "hclk", "tx_clk";
			#address-cells = <1>;
			#size-cells = <0>;
		};

		gem1: ethernet@e000c000 {
			compatible = "cdns,zynq-gem", "cdns,gem";
			reg = <0xe000c000 0x1000>;
			status = "disabled";
			interrupts = <0 45 4>;
			clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;
			clock-names = "pclk", "hclk", "tx_clk";
			#address-cells = <1>;
			#size-cells = <0>;
		};

		smcc: memory-controller@e000e000 {
			compatible = "arm,pl353-smc-r2p1", "arm,primecell";
			reg = <0xe000e000 0x0001000>;
			status = "disabled";
			clock-names = "memclk", "apb_pclk";
			clocks = <&clkc 11>, <&clkc 44>;
			ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */
				  0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */
				  0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */
			#address-cells = <2>;
			#size-cells = <1>;

			nfc0: nand-controller@0,0 {
				compatible = "arm,pl353-nand-r2p1";
				reg = <0 0 0x1000000>;
				status = "disabled";
				#address-cells = <1>;
				#size-cells = <0>;
			};
		};

		sdhci0: mmc@e0100000 {
			compatible = "arasan,sdhci-8.9a";
			status = "disabled";
			clock-names = "clk_xin", "clk_ahb";
			clocks = <&clkc 21>, <&clkc 32>;
			interrupt-parent = <&intc>;
			interrupts = <0 24 4>;
			reg = <0xe0100000 0x1000>;
		};

		sdhci1: mmc@e0101000 {
			compatible = "arasan,sdhci-8.9a";
			status = "disabled";
			clock-names = "clk_xin", "clk_ahb";
			clocks = <&clkc 22>, <&clkc 33>;
			interrupt-parent = <&intc>;
			interrupts = <0 47 4>;
			reg = <0xe0101000 0x1000>;
		};

		slcr: slcr@f8000000 {
			#address-cells = <1>;
			#size-cells = <1>;
			compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
			reg = <0xF8000000 0x1000>;
			ranges;
			clkc: clkc@100 {
				#clock-cells = <1>;
				compatible = "xlnx,ps7-clkc";
				fclk-enable = <0>;
				clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
						"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
						"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
						"fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
						"sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
						"dma", "usb0_aper", "usb1_aper", "gem0_aper",
						"gem1_aper", "sdio0_aper", "sdio1_aper",
						"spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
						"i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
						"gpio_aper", "lqspi_aper", "smc_aper", "swdt",
						"dbg_trc", "dbg_apb";
				reg = <0x100 0x100>;
			};

			rstc: rstc@200 {
				compatible = "xlnx,zynq-reset";
				reg = <0x200 0x48>;
				#reset-cells = <1>;
				syscon = <&slcr>;
			};

			pinctrl0: pinctrl@700 {
				compatible = "xlnx,pinctrl-zynq";
				reg = <0x700 0x200>;
				syscon = <&slcr>;
			};
		};

		dmac_s: dmac@f8003000 {
			compatible = "arm,pl330", "arm,primecell";
			reg = <0xf8003000 0x1000>;
			interrupt-parent = <&intc>;
			interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
				"dma4", "dma5", "dma6", "dma7";
			interrupts = <0 13 4>,
			             <0 14 4>, <0 15 4>,
			             <0 16 4>, <0 17 4>,
			             <0 40 4>, <0 41 4>,
			             <0 42 4>, <0 43 4>;
			#dma-cells = <1>;
			clocks = <&clkc 27>;
			clock-names = "apb_pclk";
		};

		devcfg: devcfg@f8007000 {
			compatible = "xlnx,zynq-devcfg-1.0";
			reg = <0xf8007000 0x100>;
			interrupt-parent = <&intc>;
			interrupts = <0 8 4>;
			clocks = <&clkc 12>;
			clock-names = "ref_clk";
			syscon = <&slcr>;
		};

		global_timer: timer@f8f00200 {
			compatible = "arm,cortex-a9-global-timer";
			reg = <0xf8f00200 0x20>;
			interrupts = <1 11 0x301>;
			interrupt-parent = <&intc>;
			clocks = <&clkc 4>;
		};

		ttc0: timer@f8001000 {
			interrupt-parent = <&intc>;
			interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
			compatible = "cdns,ttc";
			clocks = <&clkc 6>;
			reg = <0xF8001000 0x1000>;
		};

		ttc1: timer@f8002000 {
			interrupt-parent = <&intc>;
			interrupts = <0 37 4>, <0 38 4>, <0 39 4>;
			compatible = "cdns,ttc";
			clocks = <&clkc 6>;
			reg = <0xF8002000 0x1000>;
		};

		scutimer: timer@f8f00600 {
			interrupt-parent = <&intc>;
			interrupts = <1 13 0x301>;
			compatible = "arm,cortex-a9-twd-timer";
			reg = <0xf8f00600 0x20>;
			clocks = <&clkc 4>;
		};

		usb0: usb@e0002000 {
			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
			status = "disabled";
			clocks = <&clkc 28>;
			interrupt-parent = <&intc>;
			interrupts = <0 21 4>;
			reg = <0xe0002000 0x1000>;
			phy_type = "ulpi";
		};

		usb1: usb@e0003000 {
			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
			status = "disabled";
			clocks = <&clkc 29>;
			interrupt-parent = <&intc>;
			interrupts = <0 44 4>;
			reg = <0xe0003000 0x1000>;
			phy_type = "ulpi";
		};

		watchdog0: watchdog@f8005000 {
			clocks = <&clkc 45>;
			compatible = "cdns,wdt-r1p2";
			interrupt-parent = <&intc>;
			interrupts = <0 9 1>;
			reg = <0xf8005000 0x1000>;
			timeout-sec = <10>;
		};

		etb@f8801000 {
			compatible = "arm,coresight-etb10", "arm,primecell";
			reg = <0xf8801000 0x1000>;
			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
			in-ports {
				port {
					etb_in_port: endpoint {
						remote-endpoint = <&replicator_out_port1>;
					};
				};
			};
		};

		tpiu@f8803000 {
			compatible = "arm,coresight-tpiu", "arm,primecell";
			reg = <0xf8803000 0x1000>;
			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
			in-ports {
				port {
					tpiu_in_port: endpoint {
						remote-endpoint = <&replicator_out_port0>;
					};
				};
			};
		};

		funnel@f8804000 {
			compatible = "arm,coresight-static-funnel", "arm,primecell";
			reg = <0xf8804000 0x1000>;
			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";

			/* funnel output ports */
			out-ports {
				port {
					funnel_out_port: endpoint {
						remote-endpoint =
							<&replicator_in_port0>;
					};
				};
			};

			in-ports {
				#address-cells = <1>;
				#size-cells = <0>;

				/* funnel input ports */
				port@0 {
					reg = <0>;
					funnel0_in_port0: endpoint {
						remote-endpoint = <&ptm0_out_port>;
					};
				};

				port@1 {
					reg = <1>;
					funnel0_in_port1: endpoint {
						remote-endpoint = <&ptm1_out_port>;
					};
				};

				port@2 {
					reg = <2>;
					funnel0_in_port2: endpoint {
					};
				};
				/* The other input ports are not connect to anything */
			};
		};

		ptm@f889c000 {
			compatible = "arm,coresight-etm3x", "arm,primecell";
			reg = <0xf889c000 0x1000>;
			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
			cpu = <&cpu0>;
			out-ports {
				port {
					ptm0_out_port: endpoint {
						remote-endpoint = <&funnel0_in_port0>;
					};
				};
			};
		};

		ptm@f889d000 {
			compatible = "arm,coresight-etm3x", "arm,primecell";
			reg = <0xf889d000 0x1000>;
			clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
			clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
			cpu = <&cpu1>;
			out-ports {
				port {
					ptm1_out_port: endpoint {
						remote-endpoint = <&funnel0_in_port1>;
					};
				};
			};
		};
	};
};


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Xilinx CC108 board DTS
 *
 * (C) Copyright 2007-2018 Xilinx, Inc.
 * (C) Copyright 2007-2013 Michal Simek
 * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd
 *
 * Michal SIMEK <monstr@monstr.eu>
 */
/dts-v1/;
/include/ "zynq-7000.dtsi"

/ {
	model = "Xilinx CC108 board";
	compatible = "xlnx,zynq-cc108", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart0;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x20000000>;
	};

	usb_phy0: phy0 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};

	usb_phy1: phy1 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@1 {
		reg = <1>;
		device_type = "ethernet-phy";
	};
};

&sdhci1 {
	status = "okay";
	broken-cd ;
	wp-inverted ;
};

&uart0 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
};

&usb1 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy1>;
};

repo_name: angery/linux


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2021 Michael Walle <michael@walle.cc>
 */
/dts-v1/;
/include/ "zynq-7000.dtsi"

/ {
	model = "Ebang EBAZ4205";
	compatible = "ebang,ebaz4205", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x10000000>;
	};

	chosen {
		stdout-path = "serial0:115200n8";
	};
};

&clkc {
	ps-clk-frequency = <33333333>;
	fclk-enable = <8>;
};

&gem0 {
	status = "okay";
	phy-mode = "mii";
	phy-handle = <&phy>;

	/* PHY clock */
	assigned-clocks = <&clkc 18>;
	assigned-clock-rates = <25000000>;

	phy: ethernet-phy@0 {
		reg = <0>;
	};
};

&gpio0 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio0_default>;
};

&nfc0 {
	status = "okay";

	nand@0 {
		reg = <0>;
	};
};

&pinctrl0 {
	pinctrl_gpio0_default: gpio0-default {
		mux {
			groups = "gpio0_20_grp", "gpio0_32_grp";
			function = "gpio0";
		};

		conf {
			groups = "gpio0_20_grp", "gpio0_32_grp";
			io-standard = <3>;
			slew-rate = <0>;
		};

		conf-pull-up {
			pins = "MIO20", "MIO32";
			bias-disable;
		};
	};

	pinctrl_sdhci0_default: sdhci0-default {
		mux {
			groups = "sdio0_2_grp";
			function = "sdio0";
		};

		conf {
			groups = "sdio0_2_grp";
			io-standard = <3>;
			slew-rate = <0>;
			bias-disable;
		};

		mux-cd {
			groups = "gpio0_34_grp";
			function = "sdio0_cd";
		};

		conf-cd {
			groups = "gpio0_34_grp";
			io-standard = <3>;
			slew-rate = <0>;
			bias-high-impedance;
			bias-pull-up;
		};
	};

	pinctrl_uart1_default: uart1-default {
		mux {
			groups = "uart1_4_grp";
			function = "uart1";
		};

		conf {
			groups = "uart1_4_grp";
			io-standard = <3>;
			slew-rate = <0>;
		};

		conf-rx {
			pins = "MIO25";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO24";
			bias-disable;
		};
	};
};

&smcc {
	status = "okay";
};

&sdhci0 {
	status = "okay";
	disable-wp;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci0_default>;
};

&uart1 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1_default>;
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2011 - 2014 Xilinx
 * Copyright (C) 2016 Jagan Teki <jteki@openedev.com>
 */
/dts-v1/;
/include/ "zynq-7000.dtsi"

/ {
	model = "Avnet MicroZed board";
	compatible = "avnet,zynq-microzed", "xlnx,zynq-microzed", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		bootargs = "earlycon";
		stdout-path = "serial0:115200n8";
	};

	usb_phy0: phy0 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&clkc {
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@0 {
		reg = <0>;
	};
};

&sdhci0 {
	status = "okay";
};

&uart1 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb0_default>;
};

&pinctrl0 {
	pinctrl_usb0_default: usb0-default {
		mux {
			groups = "usb0_0_grp";
			function = "usb0";
		};

		conf {
			groups = "usb0_0_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-rx {
			pins = "MIO29", "MIO31", "MIO36";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO28", "MIO30", "MIO32", "MIO33", "MIO34",
			       "MIO35", "MIO37", "MIO38", "MIO39";
			bias-disable;
		};
	};
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2014 SUSE LINUX Products GmbH
 *
 * Derived from zynq-zed.dts:
 *
 *  Copyright (C) 2011 Xilinx
 *  Copyright (C) 2012 National Instruments Corp.
 *  Copyright (C) 2013 Xilinx
 */
/dts-v1/;
/include/ "zynq-7000.dtsi"

/ {
	model = "Adapteva Parallella board";
	compatible = "adapteva,parallella", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		bootargs = "root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait";
		stdout-path = "serial0:115200n8";
	};
};

&clkc {
	fclk-enable = <0xf>;
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@0 {
		/* Marvell 88E1318 */
		compatible = "ethernet-phy-id0141.0e90",
		             "ethernet-phy-ieee802.3-c22";
		reg = <0>;
		device_type = "ethernet-phy";
		marvell,reg-init = <0x3 0x10 0xff00 0x1e>,
		                   <0x3 0x11 0xfff0 0xa>;
	};
};

&i2c0 {
	status = "okay";

	isl9305: isl9305@68 {
		compatible = "isil,isl9305";
		reg = <0x68>;

		regulators {
			dcd1 {
				regulator-name = "VDD_DSP";
				regulator-always-on;
			};
			dcd2 {
				regulator-name = "1P35V";
				regulator-always-on;
			};
			ldo1 {
				regulator-name = "VDD_ADJ";
			};
			ldo2 {
				regulator-name = "VDD_GPIO";
				regulator-always-on;
			};
		};
	};
};

&sdhci1 {
	status = "okay";
};

&uart1 {
	status = "okay";
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  Copyright (C) 2011 - 2014 Xilinx
 *  Copyright (C) 2012 National Instruments Corp.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Xilinx ZC702 board";
	compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		i2c0 = &i2c0;
		serial0 = &uart1;
		mmc0 = &sdhci0;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	gpio-keys {
		compatible = "gpio-keys";
		autorepeat;
		switch-14 {
			label = "sw14";
			gpios = <&gpio0 12 0>;
			linux,code = <108>; /* down */
			wakeup-source;
			autorepeat;
		};
		switch-13 {
			label = "sw13";
			gpios = <&gpio0 14 0>;
			linux,code = <103>; /* up */
			wakeup-source;
			autorepeat;
		};
	};

	leds {
		compatible = "gpio-leds";

		led-ds23 {
			label = "ds23";
			gpios = <&gpio0 10 0>;
			linux,default-trigger = "heartbeat";
		};
	};

	usb_phy0: phy0 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&amba {
	ocm: sram@fffc0000 {
		compatible = "mmio-sram";
		reg = <0xfffc0000 0x10000>;
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0 0xfffc0000 0x10000>;
		ocm-sram@0 {
			reg = <0x0 0x10000>;
		};
	};
};

&can0 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_can0_default>;
};

&clkc {
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gem0_default>;

	ethernet_phy: ethernet-phy@7 {
		reg = <7>;
		device_type = "ethernet-phy";
	};
};

&gpio0 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio0_default>;
};

&i2c0 {
	status = "okay";
	clock-frequency = <400000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c0_default>;

	i2c-mux@74 {
		compatible = "nxp,pca9548";
		#address-cells = <1>;
		#size-cells = <0>;
		reg = <0x74>;

		i2c@0 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <0>;
			si570: clock-generator@5d {
				#clock-cells = <0>;
				compatible = "silabs,si570";
				temperature-stability = <50>;
				reg = <0x5d>;
				factory-fout = <156250000>;
				clock-frequency = <148500000>;
			};
		};

		i2c@1 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <1>;
			adv7511: hdmi-tx@39 {
				compatible = "adi,adv7511";
				reg = <0x39>;
				adi,input-depth = <8>;
				adi,input-colorspace = "yuv422";
				adi,input-clock = "1x";
				adi,input-style = <3>;
				adi,input-justification = "right";
			};
		};

		i2c@2 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <2>;
			eeprom@54 {
				compatible = "atmel,24c08";
				reg = <0x54>;
			};
		};

		i2c@3 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <3>;
			gpio@21 {
				compatible = "ti,tca6416";
				reg = <0x21>;
				gpio-controller;
				#gpio-cells = <2>;
			};
		};

		i2c@4 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <4>;
			rtc@51 {
				compatible = "nxp,pcf8563";
				reg = <0x51>;
			};
		};

		i2c@7 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <7>;
			hwmon@34 {
				compatible = "ti,ucd9248";
				reg = <0x34>;
			};
			hwmon@35 {
				compatible = "ti,ucd9248";
				reg = <0x35>;
			};
			hwmon@36 {
				compatible = "ti,ucd9248";
				reg = <0x36>;
			};
		};
	};
};

&pinctrl0 {
	pinctrl_can0_default: can0-default {
		mux {
			function = "can0";
			groups = "can0_9_grp";
		};

		conf {
			groups = "can0_9_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-rx {
			pins = "MIO46";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO47";
			bias-disable;
		};
	};

	pinctrl_gem0_default: gem0-default {
		mux {
			function = "ethernet0";
			groups = "ethernet0_0_grp";
		};

		conf {
			groups = "ethernet0_0_grp";
			slew-rate = <0>;
			io-standard = <4>;
		};

		conf-rx {
			pins = "MIO22", "MIO23", "MIO24", "MIO25", "MIO26", "MIO27";
			bias-high-impedance;
			low-power-disable;
		};

		conf-tx {
			pins = "MIO16", "MIO17", "MIO18", "MIO19", "MIO20", "MIO21";
			bias-disable;
			low-power-enable;
		};

		mux-mdio {
			function = "mdio0";
			groups = "mdio0_0_grp";
		};

		conf-mdio {
			groups = "mdio0_0_grp";
			slew-rate = <0>;
			io-standard = <1>;
			bias-disable;
		};
	};

	pinctrl_gpio0_default: gpio0-default {
		mux {
			function = "gpio0";
			groups = "gpio0_7_grp", "gpio0_8_grp", "gpio0_9_grp",
				 "gpio0_10_grp", "gpio0_11_grp", "gpio0_12_grp",
				 "gpio0_13_grp", "gpio0_14_grp";
		};

		conf {
			groups = "gpio0_7_grp", "gpio0_8_grp", "gpio0_9_grp",
				 "gpio0_10_grp", "gpio0_11_grp", "gpio0_12_grp",
				 "gpio0_13_grp", "gpio0_14_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-pull-up {
			pins = "MIO9", "MIO10", "MIO11", "MIO12", "MIO13", "MIO14";
			bias-pull-up;
		};

		conf-pull-none {
			pins = "MIO7", "MIO8";
			bias-disable;
		};
	};

	pinctrl_i2c0_default: i2c0-default {
		mux {
			groups = "i2c0_10_grp";
			function = "i2c0";
		};

		conf {
			groups = "i2c0_10_grp";
			bias-pull-up;
			slew-rate = <0>;
			io-standard = <1>;
		};
	};

	pinctrl_sdhci0_default: sdhci0-default {
		mux {
			groups = "sdio0_2_grp";
			function = "sdio0";
		};

		conf {
			groups = "sdio0_2_grp";
			slew-rate = <0>;
			io-standard = <1>;
			bias-disable;
		};

		mux-cd {
			groups = "gpio0_0_grp";
			function = "sdio0_cd";
		};

		conf-cd {
			groups = "gpio0_0_grp";
			bias-high-impedance;
			bias-pull-up;
			slew-rate = <0>;
			io-standard = <1>;
		};

		mux-wp {
			groups = "gpio0_15_grp";
			function = "sdio0_wp";
		};

		conf-wp {
			groups = "gpio0_15_grp";
			bias-high-impedance;
			bias-pull-up;
			slew-rate = <0>;
			io-standard = <1>;
		};
	};

	pinctrl_uart1_default: uart1-default {
		mux {
			groups = "uart1_10_grp";
			function = "uart1";
		};

		conf {
			groups = "uart1_10_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-rx {
			pins = "MIO49";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO48";
			bias-disable;
		};
	};

	pinctrl_usb0_default: usb0-default {
		mux {
			groups = "usb0_0_grp";
			function = "usb0";
		};

		conf {
			groups = "usb0_0_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-rx {
			pins = "MIO29", "MIO31", "MIO36";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO28", "MIO30", "MIO32", "MIO33", "MIO34",
			       "MIO35", "MIO37", "MIO38", "MIO39";
			bias-disable;
		};
	};
};

&sdhci0 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci0_default>;
};

&uart1 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1_default>;
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb0_default>;
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  Copyright (C) 2011 - 2014 Xilinx
 *  Copyright (C) 2012 National Instruments Corp.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Xilinx ZC706 board";
	compatible = "xlnx,zynq-zc706", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		i2c0 = &i2c0;
		serial0 = &uart1;
		mmc0 = &sdhci0;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	usb_phy0: phy0 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&clkc {
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gem0_default>;

	ethernet_phy: ethernet-phy@7 {
		reg = <7>;
		device_type = "ethernet-phy";
	};
};

&gpio0 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio0_default>;
};

&i2c0 {
	status = "okay";
	clock-frequency = <400000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c0_default>;

	i2c-mux@74 {
		compatible = "nxp,pca9548";
		#address-cells = <1>;
		#size-cells = <0>;
		reg = <0x74>;

		i2c@0 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <0>;
			si570: clock-generator@5d {
				#clock-cells = <0>;
				compatible = "silabs,si570";
				temperature-stability = <50>;
				reg = <0x5d>;
				factory-fout = <156250000>;
				clock-frequency = <148500000>;
			};
		};

		i2c@1 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <1>;
			adv7511: hdmi-tx@39 {
				compatible = "adi,adv7511";
				reg = <0x39>;
				adi,input-depth = <8>;
				adi,input-colorspace = "yuv422";
				adi,input-clock = "1x";
				adi,input-style = <3>;
				adi,input-justification = "evenly";
			};
		};

		i2c@2 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <2>;
			eeprom@54 {
				compatible = "atmel,24c08";
				reg = <0x54>;
			};
		};

		i2c@3 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <3>;
			gpio@21 {
				compatible = "ti,tca6416";
				reg = <0x21>;
				gpio-controller;
				#gpio-cells = <2>;
			};
		};

		i2c@4 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <4>;
			rtc@51 {
				compatible = "nxp,pcf8563";
				reg = <0x51>;
			};
		};

		i2c@7 {
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <7>;
			ucd90120@65 {
				compatible = "ti,ucd90120";
				reg = <0x65>;
			};
		};
	};
};

&pinctrl0 {
	pinctrl_gem0_default: gem0-default {
		mux {
			function = "ethernet0";
			groups = "ethernet0_0_grp";
		};

		conf {
			groups = "ethernet0_0_grp";
			slew-rate = <0>;
			io-standard = <4>;
		};

		conf-rx {
			pins = "MIO22", "MIO23", "MIO24", "MIO25", "MIO26", "MIO27";
			bias-high-impedance;
			low-power-disable;
		};

		conf-tx {
			pins = "MIO16", "MIO17", "MIO18", "MIO19", "MIO20", "MIO21";
			low-power-enable;
			bias-disable;
		};

		mux-mdio {
			function = "mdio0";
			groups = "mdio0_0_grp";
		};

		conf-mdio {
			groups = "mdio0_0_grp";
			slew-rate = <0>;
			io-standard = <1>;
			bias-disable;
		};
	};

	pinctrl_gpio0_default: gpio0-default {
		mux {
			function = "gpio0";
			groups = "gpio0_7_grp", "gpio0_46_grp", "gpio0_47_grp";
		};

		conf {
			groups = "gpio0_7_grp", "gpio0_46_grp", "gpio0_47_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-pull-up {
			pins = "MIO46", "MIO47";
			bias-pull-up;
		};

		conf-pull-none {
			pins = "MIO7";
			bias-disable;
		};
	};

	pinctrl_i2c0_default: i2c0-default {
		mux {
			groups = "i2c0_10_grp";
			function = "i2c0";
		};

		conf {
			groups = "i2c0_10_grp";
			bias-pull-up;
			slew-rate = <0>;
			io-standard = <1>;
		};
	};

	pinctrl_sdhci0_default: sdhci0-default {
		mux {
			groups = "sdio0_2_grp";
			function = "sdio0";
		};

		conf {
			groups = "sdio0_2_grp";
			slew-rate = <0>;
			io-standard = <1>;
			bias-disable;
		};

		mux-cd {
			groups = "gpio0_14_grp";
			function = "sdio0_cd";
		};

		conf-cd {
			groups = "gpio0_14_grp";
			bias-high-impedance;
			bias-pull-up;
			slew-rate = <0>;
			io-standard = <1>;
		};

		mux-wp {
			groups = "gpio0_15_grp";
			function = "sdio0_wp";
		};

		conf-wp {
			groups = "gpio0_15_grp";
			bias-high-impedance;
			bias-pull-up;
			slew-rate = <0>;
			io-standard = <1>;
		};
	};

	pinctrl_uart1_default: uart1-default {
		mux {
			groups = "uart1_10_grp";
			function = "uart1";
		};

		conf {
			groups = "uart1_10_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-rx {
			pins = "MIO49";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO48";
			bias-disable;
		};
	};

	pinctrl_usb0_default: usb0-default {
		mux {
			groups = "usb0_0_grp";
			function = "usb0";
		};

		conf {
			groups = "usb0_0_grp";
			slew-rate = <0>;
			io-standard = <1>;
		};

		conf-rx {
			pins = "MIO29", "MIO31", "MIO36";
			bias-high-impedance;
		};

		conf-tx {
			pins = "MIO28", "MIO30", "MIO32", "MIO33", "MIO34",
			       "MIO35", "MIO37", "MIO38", "MIO39";
			bias-disable;
		};
	};
};

&sdhci0 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_sdhci0_default>;
};

&uart1 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1_default>;
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb0_default>;
};


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Xilinx ZC770 XM010 board DTS
 *
 * Copyright (C) 2013-2018 Xilinx, Inc.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Xilinx ZC770 XM010 board";
	compatible = "xlnx,zynq-zc770-xm010", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		i2c0 = &i2c0;
		serial0 = &uart1;
		spi1 = &spi1;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	usb_phy0: phy0 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&can0 {
	status = "okay";
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@7 {
		reg = <7>;
		device_type = "ethernet-phy";
	};
};

&i2c0 {
	status = "okay";
	clock-frequency = <400000>;

	eeprom: eeprom@52 {
		compatible = "atmel,24c02";
		reg = <0x52>;
	};

};

&sdhci0 {
	status = "okay";
};

&spi1 {
	status = "okay";
	num-cs = <4>;
	is-decoded-cs = <0>;
	flash@1 {
		compatible = "sst25wf080", "jedec,spi-nor";
		reg = <1>;
		spi-max-frequency = <1000000>;
		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;
			partition@0 {
				label = "data";
				reg = <0x0 0x100000>;
			};
		};
	};
};

&uart1 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
};


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Xilinx ZC770 XM011 board DTS
 *
 * Copyright (C) 2013-2018 Xilinx, Inc.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Xilinx ZC770 XM011 board";
	compatible = "xlnx,zynq-zc770-xm011", "xlnx,zynq-7000";

	aliases {
		i2c0 = &i2c1;
		serial0 = &uart1;
		spi0 = &spi0;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	usb_phy1: phy1 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&can0 {
	status = "okay";
};

&i2c1 {
	status = "okay";
	clock-frequency = <400000>;

	eeprom: eeprom@52 {
		compatible = "atmel,24c02";
		reg = <0x52>;
	};
};

&spi0 {
	status = "okay";
	num-cs = <4>;
	is-decoded-cs = <0>;
};

&uart1 {
	status = "okay";
};

&usb1 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy1>;
};


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Xilinx ZC770 XM012 board DTS
 *
 * Copyright (C) 2013-2018 Xilinx, Inc.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Xilinx ZC770 XM012 board";
	compatible = "xlnx,zynq-zc770-xm012", "xlnx,zynq-7000";

	aliases {
		i2c0 = &i2c0;
		i2c1 = &i2c1;
		serial0 = &uart1;
		spi0 = &spi1;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};
};

&can1 {
	status = "okay";
};

&i2c0 {
	status = "okay";
	clock-frequency = <400000>;

	eeprom0: eeprom@52 {
		compatible = "atmel,24c02";
		reg = <0x52>;
	};
};

&i2c1 {
	status = "okay";
	clock-frequency = <400000>;

	eeprom1: eeprom@52 {
		compatible = "atmel,24c02";
		reg = <0x52>;
	};
};

&spi1 {
	status = "okay";
	num-cs = <4>;
	is-decoded-cs = <0>;
};

&uart1 {
	status = "okay";
};


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Xilinx ZC770 XM013 board DTS
 *
 * Copyright (C) 2013 Xilinx, Inc.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Xilinx ZC770 XM013 board";
	compatible = "xlnx,zynq-zc770-xm013", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem1;
		i2c0 = &i2c1;
		serial0 = &uart0;
		spi1 = &spi0;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};
};

&can1 {
	status = "okay";
};

&gem1 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@7 {
		reg = <7>;
		device_type = "ethernet-phy";
	};
};

&i2c1 {
	status = "okay";
	clock-frequency = <400000>;

	si570: clock-generator@55 {
		#clock-cells = <0>;
		compatible = "silabs,si570";
		temperature-stability = <50>;
		reg = <0x55>;
		factory-fout = <156250000>;
		clock-frequency = <148500000>;
	};
};

&spi0 {
	status = "okay";
	num-cs = <4>;
	is-decoded-cs = <0>;
	eeprom: eeprom@2 {
		compatible = "atmel,at25";
		reg = <2>;
		spi-max-frequency = <1000000>;
		size = <8192>;
		address-width = <16>;
		pagesize = <32>;
	};
};

&uart0 {
	status = "okay";
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  Copyright (C) 2011 - 2014 Xilinx
 *  Copyright (C) 2012 National Instruments Corp.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Avnet ZedBoard board";
	compatible = "avnet,zynq-zed", "xlnx,zynq-zed", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
		mmc0 = &sdhci0;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x20000000>;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	usb_phy0: phy0 {
		compatible = "usb-nop-xceiv";
		#phy-cells = <0>;
	};
};

&clkc {
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@0 {
		reg = <0>;
		device_type = "ethernet-phy";
	};
};

&sdhci0 {
	status = "okay";
};

&uart1 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  Copyright (C) 2015 Andrea Merello <adnrea.merello@gmail.com>
 *  Copyright (C) 2017 Alexander Graf <agraf@suse.de>
 *
 *  Based on zynq-zed.dts which is:
 *  Copyright (C) 2011 - 2014 Xilinx
 *  Copyright (C) 2012 National Instruments Corp.
 *
 */

/dts-v1/;
/include/ "zynq-7000.dtsi"

/ {
	compatible = "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
		serial1 = &uart0;
		mmc0 = &sdhci0;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		stdout-path = "serial0:115200n8";
	};

	gpio-leds {
		compatible = "gpio-leds";
		usr-led1 {
			label = "usr-led1";
			gpios = <&gpio0 0x0 0x1>;
			default-state = "off";
		};

		usr-led2 {
			label = "usr-led2";
			gpios = <&gpio0 0x9 0x1>;
			default-state = "off";
		};
	};

	gpio-keys {
		compatible = "gpio-keys";
		autorepeat;
		key {
			label = "K1";
			gpios = <&gpio0 0x32 0x1>;
			linux,code = <0x66>;
			wakeup-source;
			autorepeat;
		};
	};
};

&clkc {
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@0 {
	};
};

&sdhci0 {
	status = "okay";
};

&uart0 {
	status = "okay";
};

&uart1 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
};

&can0 {
	status = "okay";
};

&i2c0 {
	status = "okay";
	clock-frequency = <400000>;

	stlm75@49 {
		status = "okay";
		compatible = "lm75";
		reg = <0x49>;
	};

	accelerometer@53 {
		compatible = "adi,adxl345";
		reg = <0x53>;
		interrupt-parent = <&intc>;
		interrupts = <0x0 0x1e 0x4>;
	};
};


code:
// SPDX-License-Identifier: GPL-2.0

/dts-v1/;
/include/ "zynq-zturn-common.dtsi"

/ {
	model = "Zynq Z-Turn MYIR Board V5";
	compatible = "myir,zynq-zturn-v5", "xlnx,zynq-7000";
};

&gem0 {
	ethernet_phy: ethernet-phy@0 {
		reg = <0x3>;
	};
};


code:
// SPDX-License-Identifier: GPL-2.0

/dts-v1/;
/include/ "zynq-zturn-common.dtsi"

/ {
	model = "Zynq Z-Turn MYIR Board";
	compatible = "myir,zynq-zturn", "xlnx,zynq-7000";
};

&gem0 {
	ethernet_phy: ethernet-phy@0 {
		reg = <0x0>;
	};
};


code:
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
#include "zynq-7000.dtsi"
#include <dt-bindings/gpio/gpio.h>

/ {
	model = "Digilent Zybo Z7 board";
	compatible = "digilent,zynq-zybo-z7", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	gpio-leds {
		compatible = "gpio-leds";

		led-ld4 {
			label = "zynq-zybo-z7:green:ld4";
			gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
		};
	};

	usb_phy0: phy0 {
		#phy-cells = <0>;
		compatible = "usb-nop-xceiv";
		reset-gpios = <&gpio0 46 GPIO_ACTIVE_LOW>;
	};
};

&clkc {
	ps-clk-frequency = <33333333>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@0 {
		reg = <0>;
		device_type = "ethernet-phy";
	};
};

&sdhci0 {
	status = "okay";
};

&uart1 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
};


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  Copyright (C) 2011 - 2014 Xilinx
 *  Copyright (C) 2012 National Instruments Corp.
 */
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
	model = "Digilent Zybo board";
	compatible = "digilent,zynq-zybo", "xlnx,zynq-7000";

	aliases {
		ethernet0 = &gem0;
		serial0 = &uart1;
		mmc0 = &sdhci0;
	};

	memory@0 {
		device_type = "memory";
		reg = <0x0 0x20000000>;
	};

	chosen {
		bootargs = "";
		stdout-path = "serial0:115200n8";
	};

	usb_phy0: phy0 {
		#phy-cells = <0>;
		compatible = "usb-nop-xceiv";
		reset-gpios = <&gpio0 46 1>;
	};
};

&clkc {
	ps-clk-frequency = <50000000>;
};

&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy>;

	ethernet_phy: ethernet-phy@0 {
		reg = <0>;
		device_type = "ethernet-phy";
	};
};

&sdhci0 {
	status = "okay";
};

&uart1 {
	status = "okay";
};

&usb0 {
	status = "okay";
	dr_mode = "host";
	usb-phy = <&usb_phy0>;
};


code:
#!/bin/sh
#
# 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) 1995 by Linus Torvalds
#
# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
# Adapted from code in arch/i386/boot/install.sh by Russell King
#
# "make install" script for arm architecture
#
# Arguments:
#   $1 - kernel version
#   $2 - kernel image file
#   $3 - kernel map file
#   $4 - default install path (blank if root directory)

if [ "$(basename $2)" = "zImage" ]; then
# Compressed install
  echo "Installing compressed kernel"
  base=vmlinuz
else
# Normal install
  echo "Installing normal kernel"
  base=vmlinux
fi

if [ -f $4/$base-$1 ]; then
  mv $4/$base-$1 $4/$base-$1.old
fi
cat $2 > $4/$base-$1

# Install system map file
if [ -f $4/System.map-$1 ]; then
  mv $4/System.map-$1 $4/System.map-$1.old
fi
cp $3 $4/System.map-$1

if [ -x /sbin/loadmap ]; then
  /sbin/loadmap
else
  echo "You have to install it yourself"
fi


code:
# SPDX-License-Identifier: GPL-2.0
config SA1111
	bool
	select ZONE_DMA if ARCH_SA1100

config KRAIT_L2_ACCESSORS
	bool

config SHARP_LOCOMO
	bool

config SHARP_PARAM
	bool

config SHARP_SCOOP
	bool

path: arch/arm/common/Kconfig


code:
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#

obj-y				+= firmware.o

obj-$(CONFIG_SA1111)		+= sa1111.o
obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o
obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
obj-$(CONFIG_CPU_V7)		+= secure_cntvoff.o
obj-$(CONFIG_MCPM)		+= mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o
CFLAGS_REMOVE_mcpm_entry.o	= -pg
obj-$(CONFIG_BL_SWITCHER)	+= bL_switcher.o
obj-$(CONFIG_BL_SWITCHER_DUMMY_IF) += bL_switcher_dummy_if.o

path: arch/arm/common/Makefile


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/common/bL_switcher.c -- big.LITTLE cluster switcher core driver
 *
 * Created by:	Nicolas Pitre, March 2012
 * Copyright:	(C) 2012-2013  Linaro Limited
 */

#include <linux/atomic.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched/signal.h>
#include <uapi/linux/sched/types.h>
#include <linux/interrupt.h>
#include <linux/cpu_pm.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <linux/hrtimer.h>
#include <linux/tick.h>
#include <linux/notifier.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/moduleparam.h>

#include <asm/smp_plat.h>
#include <asm/cputype.h>
#include <asm/suspend.h>
#include <asm/mcpm.h>
#include <asm/bL_switcher.h>

#define CREATE_TRACE_POINTS
#include <trace/events/power_cpu_migrate.h>

/*
 * Use our own MPIDR accessors as the generic ones in asm/cputype.h have
 * __attribute_const__ and we don't want the compiler to assume any
 * constness here as the value _does_ change along some code paths.
 */

static int read_mpidr(void)
{
	unsigned int id;
	asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (id));
	return id & MPIDR_HWID_BITMASK;
}

/*
 * bL switcher core code.
 */

static void bL_do_switch(void *_arg)
{
	unsigned ib_mpidr, ib_cpu, ib_cluster;
	long volatile handshake, **handshake_ptr = _arg;

	pr_debug("%s\n", __func__);

	ib_mpidr = cpu_logical_map(smp_processor_id());
	ib_cpu = MPIDR_AFFINITY_LEVEL(ib_mpidr, 0);
	ib_cluster = MPIDR_AFFINITY_LEVEL(ib_mpidr, 1);

	/* Advertise our handshake location */
	if (handshake_ptr) {
		handshake = 0;
		*handshake_ptr = &handshake;
	} else
		handshake = -1;

	/*
	 * Our state has been saved at this point.  Let's release our
	 * inbound CPU.
	 */
	mcpm_set_entry_vector(ib_cpu, ib_cluster, cpu_resume);
	sev();

	/*
	 * From this point, we must assume that our counterpart CPU might
	 * have taken over in its parallel world already, as if execution
	 * just returned from cpu_suspend().  It is therefore important to
	 * be very careful not to make any change the other guy is not
	 * expecting.  This is why we need stack isolation.
	 *
	 * Fancy under cover tasks could be performed here.  For now
	 * we have none.
	 */

	/*
	 * Let's wait until our inbound is alive.
	 */
	while (!handshake) {
		wfe();
		smp_mb();
	}

	/* Let's put ourself down. */
	mcpm_cpu_power_down();

	/* should never get here */
	BUG();
}

/*
 * Stack isolation.  To ensure 'current' remains valid, we just use another
 * piece of our thread's stack space which should be fairly lightly used.
 * The selected area starts just above the thread_info structure located
 * at the very bottom of the stack, aligned to a cache line, and indexed
 * with the cluster number.
 */
#define STACK_SIZE 512
extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
static int bL_switchpoint(unsigned long _arg)
{
	unsigned int mpidr = read_mpidr();
	unsigned int clusterid = MPIDR_AFFINITY_LEVEL(mpidr, 1);
	void *stack = current_thread_info() + 1;
	stack = PTR_ALIGN(stack, L1_CACHE_BYTES);
	stack += clusterid * STACK_SIZE + STACK_SIZE;
	call_with_stack(bL_do_switch, (void *)_arg, stack);
	BUG();
}

/*
 * Generic switcher interface
 */

static unsigned int bL_gic_id[MAX_CPUS_PER_CLUSTER][MAX_NR_CLUSTERS];
static int bL_switcher_cpu_pairing[NR_CPUS];

/*
 * bL_switch_to - Switch to a specific cluster for the current CPU
 * @new_cluster_id: the ID of the cluster to switch to.
 *
 * This function must be called on the CPU to be switched.
 * Returns 0 on success, else a negative status code.
 */
static int bL_switch_to(unsigned int new_cluster_id)
{
	unsigned int mpidr, this_cpu, that_cpu;
	unsigned int ob_mpidr, ob_cpu, ob_cluster, ib_mpidr, ib_cpu, ib_cluster;
	struct completion inbound_alive;
	long volatile *handshake_ptr;
	int ipi_nr, ret;

	this_cpu = smp_processor_id();
	ob_mpidr = read_mpidr();
	ob_cpu = MPIDR_AFFINITY_LEVEL(ob_mpidr, 0);
	ob_cluster = MPIDR_AFFINITY_LEVEL(ob_mpidr, 1);
	BUG_ON(cpu_logical_map(this_cpu) != ob_mpidr);

	if (new_cluster_id == ob_cluster)
		return 0;

	that_cpu = bL_switcher_cpu_pairing[this_cpu];
	ib_mpidr = cpu_logical_map(that_cpu);
	ib_cpu = MPIDR_AFFINITY_LEVEL(ib_mpidr, 0);
	ib_cluster = MPIDR_AFFINITY_LEVEL(ib_mpidr, 1);

	pr_debug("before switch: CPU %d MPIDR %#x -> %#x\n",
		 this_cpu, ob_mpidr, ib_mpidr);

	this_cpu = smp_processor_id();

	/* Close the gate for our entry vectors */
	mcpm_set_entry_vector(ob_cpu, ob_cluster, NULL);
	mcpm_set_entry_vector(ib_cpu, ib_cluster, NULL);

	/* Install our "inbound alive" notifier. */
	init_completion(&inbound_alive);
	ipi_nr = register_ipi_completion(&inbound_alive, this_cpu);
	ipi_nr |= ((1 << 16) << bL_gic_id[ob_cpu][ob_cluster]);
	mcpm_set_early_poke(ib_cpu, ib_cluster, gic_get_sgir_physaddr(), ipi_nr);

	/*
	 * Let's wake up the inbound CPU now in case it requires some delay
	 * to come online, but leave it gated in our entry vector code.
	 */
	ret = mcpm_cpu_power_up(ib_cpu, ib_cluster);
	if (ret) {
		pr_err("%s: mcpm_cpu_power_up() returned %d\n", __func__, ret);
		return ret;
	}

	/*
	 * Raise a SGI on the inbound CPU to make sure it doesn't stall
	 * in a possible WFI, such as in bL_power_down().
	 */
	gic_send_sgi(bL_gic_id[ib_cpu][ib_cluster], 0);

	/*
	 * Wait for the inbound to come up.  This allows for other
	 * tasks to be scheduled in the mean time.
	 */
	wait_for_completion(&inbound_alive);
	mcpm_set_early_poke(ib_cpu, ib_cluster, 0, 0);

	/*
	 * From this point we are entering the switch critical zone
	 * and can't take any interrupts anymore.
	 */
	local_irq_disable();
	local_fiq_disable();
	trace_cpu_migrate_begin(ktime_get_real_ns(), ob_mpidr);

	/* redirect GIC's SGIs to our counterpart */
	gic_migrate_target(bL_gic_id[ib_cpu][ib_cluster]);

	tick_suspend_local();

	ret = cpu_pm_enter();

	/* we can not tolerate errors at this point */
	if (ret)
		panic("%s: cpu_pm_enter() returned %d\n", __func__, ret);

	/* Swap the physical CPUs in the logical map for this logical CPU. */
	cpu_logical_map(this_cpu) = ib_mpidr;
	cpu_logical_map(that_cpu) = ob_mpidr;

	/* Let's do the actual CPU switch. */
	ret = cpu_suspend((unsigned long)&handshake_ptr, bL_switchpoint);
	if (ret > 0)
		panic("%s: cpu_suspend() returned %d\n", __func__, ret);

	/* We are executing on the inbound CPU at this point */
	mpidr = read_mpidr();
	pr_debug("after switch: CPU %d MPIDR %#x\n", this_cpu, mpidr);
	BUG_ON(mpidr != ib_mpidr);

	mcpm_cpu_powered_up();

	ret = cpu_pm_exit();

	tick_resume_local();

	trace_cpu_migrate_finish(ktime_get_real_ns(), ib_mpidr);
	local_fiq_enable();
	local_irq_enable();

	*handshake_ptr = 1;
	dsb_sev();

	if (ret)
		pr_err("%s exiting with error %d\n", __func__, ret);
	return ret;
}

struct bL_thread {
	spinlock_t lock;
	struct task_struct *task;
	wait_queue_head_t wq;
	int wanted_cluster;
	struct completion started;
	bL_switch_completion_handler completer;
	void *completer_cookie;
};

static struct bL_thread bL_threads[NR_CPUS];

static int bL_switcher_thread(void *arg)
{
	struct bL_thread *t = arg;
	int cluster;
	bL_switch_completion_handler completer;
	void *completer_cookie;

	sched_set_fifo_low(current);
	complete(&t->started);

	do {
		if (signal_pending(current))
			flush_signals(current);
		wait_event_interruptible(t->wq,
				t->wanted_cluster != -1 ||
				kthread_should_stop());

		spin_lock(&t->lock);
		cluster = t->wanted_cluster;
		completer = t->completer;
		completer_cookie = t->completer_cookie;
		t->wanted_cluster = -1;
		t->completer = NULL;
		spin_unlock(&t->lock);

		if (cluster != -1) {
			bL_switch_to(cluster);

			if (completer)
				completer(completer_cookie);
		}
	} while (!kthread_should_stop());

	return 0;
}

static struct task_struct *bL_switcher_thread_create(int cpu, void *arg)
{
	struct task_struct *task;

	task = kthread_create_on_node(bL_switcher_thread, arg,
				      cpu_to_node(cpu), "kswitcher_%d", cpu);
	if (!IS_ERR(task)) {
		kthread_bind(task, cpu);
		wake_up_process(task);
	} else
		pr_err("%s failed for CPU %d\n", __func__, cpu);
	return task;
}

/*
 * bL_switch_request_cb - Switch to a specific cluster for the given CPU,
 *      with completion notification via a callback
 *
 * @cpu: the CPU to switch
 * @new_cluster_id: the ID of the cluster to switch to.
 * @completer: switch completion callback.  if non-NULL,
 *	@completer(@completer_cookie) will be called on completion of
 *	the switch, in non-atomic context.
 * @completer_cookie: opaque context argument for @completer.
 *
 * This function causes a cluster switch on the given CPU by waking up
 * the appropriate switcher thread.  This function may or may not return
 * before the switch has occurred.
 *
 * If a @completer callback function is supplied, it will be called when
 * the switch is complete.  This can be used to determine asynchronously
 * when the switch is complete, regardless of when bL_switch_request()
 * returns.  When @completer is supplied, no new switch request is permitted
 * for the affected CPU until after the switch is complete, and @completer
 * has returned.
 */
int bL_switch_request_cb(unsigned int cpu, unsigned int new_cluster_id,
			 bL_switch_completion_handler completer,
			 void *completer_cookie)
{
	struct bL_thread *t;

	if (cpu >= ARRAY_SIZE(bL_threads)) {
		pr_err("%s: cpu %d out of bounds\n", __func__, cpu);
		return -EINVAL;
	}

	t = &bL_threads[cpu];

	if (IS_ERR(t->task))
		return PTR_ERR(t->task);
	if (!t->task)
		return -ESRCH;

	spin_lock(&t->lock);
	if (t->completer) {
		spin_unlock(&t->lock);
		return -EBUSY;
	}
	t->completer = completer;
	t->completer_cookie = completer_cookie;
	t->wanted_cluster = new_cluster_id;
	spin_unlock(&t->lock);
	wake_up(&t->wq);
	return 0;
}
EXPORT_SYMBOL_GPL(bL_switch_request_cb);

/*
 * Activation and configuration code.
 */

static DEFINE_MUTEX(bL_switcher_activation_lock);
static BLOCKING_NOTIFIER_HEAD(bL_activation_notifier);
static unsigned int bL_switcher_active;
static unsigned int bL_switcher_cpu_original_cluster[NR_CPUS];
static cpumask_t bL_switcher_removed_logical_cpus;

int bL_switcher_register_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&bL_activation_notifier, nb);
}
EXPORT_SYMBOL_GPL(bL_switcher_register_notifier);

int bL_switcher_unregister_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&bL_activation_notifier, nb);
}
EXPORT_SYMBOL_GPL(bL_switcher_unregister_notifier);

static int bL_activation_notify(unsigned long val)
{
	int ret;

	ret = blocking_notifier_call_chain(&bL_activation_notifier, val, NULL);
	if (ret & NOTIFY_STOP_MASK)
		pr_err("%s: notifier chain failed with status 0x%x\n",
			__func__, ret);
	return notifier_to_errno(ret);
}

static void bL_switcher_restore_cpus(void)
{
	int i;

	for_each_cpu(i, &bL_switcher_removed_logical_cpus) {
		struct device *cpu_dev = get_cpu_device(i);
		int ret = device_online(cpu_dev);
		if (ret)
			dev_err(cpu_dev, "switcher: unable to restore CPU\n");
	}
}

static int bL_switcher_halve_cpus(void)
{
	int i, j, cluster_0, gic_id, ret;
	unsigned int cpu, cluster, mask;
	cpumask_t available_cpus;

	/* First pass to validate what we have */
	mask = 0;
	for_each_online_cpu(i) {
		cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0);
		cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1);
		if (cluster >= 2) {
			pr_err("%s: only dual cluster systems are supported\n", __func__);
			return -EINVAL;
		}
		if (WARN_ON(cpu >= MAX_CPUS_PER_CLUSTER))
			return -EINVAL;
		mask |= (1 << cluster);
	}
	if (mask != 3) {
		pr_err("%s: no CPU pairing possible\n", __func__);
		return -EINVAL;
	}

	/*
	 * Now let's do the pairing.  We match each CPU with another CPU
	 * from a different cluster.  To get a uniform scheduling behavior
	 * without fiddling with CPU topology and compute capacity data,
	 * we'll use logical CPUs initially belonging to the same cluster.
	 */
	memset(bL_switcher_cpu_pairing, -1, sizeof(bL_switcher_cpu_pairing));
	cpumask_copy(&available_cpus, cpu_online_mask);
	cluster_0 = -1;
	for_each_cpu(i, &available_cpus) {
		int match = -1;
		cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1);
		if (cluster_0 == -1)
			cluster_0 = cluster;
		if (cluster != cluster_0)
			continue;
		cpumask_clear_cpu(i, &available_cpus);
		for_each_cpu(j, &available_cpus) {
			cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(j), 1);
			/*
			 * Let's remember the last match to create "odd"
			 * pairings on purpose in order for other code not
			 * to assume any relation between physical and
			 * logical CPU numbers.
			 */
			if (cluster != cluster_0)
				match = j;
		}
		if (match != -1) {
			bL_switcher_cpu_pairing[i] = match;
			cpumask_clear_cpu(match, &available_cpus);
			pr_info("CPU%d paired with CPU%d\n", i, match);
		}
	}

	/*
	 * Now we disable the unwanted CPUs i.e. everything that has no
	 * pairing information (that includes the pairing counterparts).
	 */
	cpumask_clear(&bL_switcher_removed_logical_cpus);
	for_each_online_cpu(i) {
		cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0);
		cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1);

		/* Let's take note of the GIC ID for this CPU */
		gic_id = gic_get_cpu_id(i);
		if (gic_id < 0) {
			pr_err("%s: bad GIC ID for CPU %d\n", __func__, i);
			bL_switcher_restore_cpus();
			return -EINVAL;
		}
		bL_gic_id[cpu][cluster] = gic_id;
		pr_info("GIC ID for CPU %u cluster %u is %u\n",
			cpu, cluster, gic_id);

		if (bL_switcher_cpu_pairing[i] != -1) {
			bL_switcher_cpu_original_cluster[i] = cluster;
			continue;
		}

		ret = device_offline(get_cpu_device(i));
		if (ret) {
			bL_switcher_restore_cpus();
			return ret;
		}
		cpumask_set_cpu(i, &bL_switcher_removed_logical_cpus);
	}

	return 0;
}

/* Determine the logical CPU a given physical CPU is grouped on. */
int bL_switcher_get_logical_index(u32 mpidr)
{
	int cpu;

	if (!bL_switcher_active)
		return -EUNATCH;

	mpidr &= MPIDR_HWID_BITMASK;
	for_each_online_cpu(cpu) {
		int pairing = bL_switcher_cpu_pairing[cpu];
		if (pairing == -1)
			continue;
		if ((mpidr == cpu_logical_map(cpu)) ||
		    (mpidr == cpu_logical_map(pairing)))
			return cpu;
	}
	return -EINVAL;
}

static void bL_switcher_trace_trigger_cpu(void *__always_unused info)
{
	trace_cpu_migrate_current(ktime_get_real_ns(), read_mpidr());
}

int bL_switcher_trace_trigger(void)
{
	preempt_disable();

	bL_switcher_trace_trigger_cpu(NULL);
	smp_call_function(bL_switcher_trace_trigger_cpu, NULL, true);

	preempt_enable();

	return 0;
}
EXPORT_SYMBOL_GPL(bL_switcher_trace_trigger);

static int bL_switcher_enable(void)
{
	int cpu, ret;

	mutex_lock(&bL_switcher_activation_lock);
	lock_device_hotplug();
	if (bL_switcher_active) {
		unlock_device_hotplug();
		mutex_unlock(&bL_switcher_activation_lock);
		return 0;
	}

	pr_info("big.LITTLE switcher initializing\n");

	ret = bL_activation_notify(BL_NOTIFY_PRE_ENABLE);
	if (ret)
		goto error;

	ret = bL_switcher_halve_cpus();
	if (ret)
		goto error;

	bL_switcher_trace_trigger();

	for_each_online_cpu(cpu) {
		struct bL_thread *t = &bL_threads[cpu];
		spin_lock_init(&t->lock);
		init_waitqueue_head(&t->wq);
		init_completion(&t->started);
		t->wanted_cluster = -1;
		t->task = bL_switcher_thread_create(cpu, t);
	}

	bL_switcher_active = 1;
	bL_activation_notify(BL_NOTIFY_POST_ENABLE);
	pr_info("big.LITTLE switcher initialized\n");
	goto out;

error:
	pr_warn("big.LITTLE switcher initialization failed\n");
	bL_activation_notify(BL_NOTIFY_POST_DISABLE);

out:
	unlock_device_hotplug();
	mutex_unlock(&bL_switcher_activation_lock);
	return ret;
}

#ifdef CONFIG_SYSFS

static void bL_switcher_disable(void)
{
	unsigned int cpu, cluster;
	struct bL_thread *t;
	struct task_struct *task;

	mutex_lock(&bL_switcher_activation_lock);
	lock_device_hotplug();

	if (!bL_switcher_active)
		goto out;

	if (bL_activation_notify(BL_NOTIFY_PRE_DISABLE) != 0) {
		bL_activation_notify(BL_NOTIFY_POST_ENABLE);
		goto out;
	}

	bL_switcher_active = 0;

	/*
	 * To deactivate the switcher, we must shut down the switcher
	 * threads to prevent any other requests from being accepted.
	 * Then, if the final cluster for given logical CPU is not the
	 * same as the original one, we'll recreate a switcher thread
	 * just for the purpose of switching the CPU back without any
	 * possibility for interference from external requests.
	 */
	for_each_online_cpu(cpu) {
		t = &bL_threads[cpu];
		task = t->task;
		t->task = NULL;
		if (!task || IS_ERR(task))
			continue;
		kthread_stop(task);
		/* no more switch may happen on this CPU at this point */
		cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1);
		if (cluster == bL_switcher_cpu_original_cluster[cpu])
			continue;
		init_completion(&t->started);
		t->wanted_cluster = bL_switcher_cpu_original_cluster[cpu];
		task = bL_switcher_thread_create(cpu, t);
		if (!IS_ERR(task)) {
			wait_for_completion(&t->started);
			kthread_stop(task);
			cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1);
			if (cluster == bL_switcher_cpu_original_cluster[cpu])
				continue;
		}
		/* If execution gets here, we're in trouble. */
		pr_crit("%s: unable to restore original cluster for CPU %d\n",
			__func__, cpu);
		pr_crit("%s: CPU %d can't be restored\n",
			__func__, bL_switcher_cpu_pairing[cpu]);
		cpumask_clear_cpu(bL_switcher_cpu_pairing[cpu],
				  &bL_switcher_removed_logical_cpus);
	}

	bL_switcher_restore_cpus();
	bL_switcher_trace_trigger();

	bL_activation_notify(BL_NOTIFY_POST_DISABLE);

out:
	unlock_device_hotplug();
	mutex_unlock(&bL_switcher_activation_lock);
}

static ssize_t bL_switcher_active_show(struct kobject *kobj,
		struct kobj_attribute *attr, char *buf)
{
	return sprintf(buf, "%u\n", bL_switcher_active);
}

static ssize_t bL_switcher_active_store(struct kobject *kobj,
		struct kobj_attribute *attr, const char *buf, size_t count)
{
	int ret;

	switch (buf[0]) {
	case '0':
		bL_switcher_disable();
		ret = 0;
		break;
	case '1':
		ret = bL_switcher_enable();
		break;
	default:
		ret = -EINVAL;
	}

	return (ret >= 0) ? count : ret;
}

static ssize_t bL_switcher_trace_trigger_store(struct kobject *kobj,
		struct kobj_attribute *attr, const char *buf, size_t count)
{
	int ret = bL_switcher_trace_trigger();

	return ret ? ret : count;
}

static struct kobj_attribute bL_switcher_active_attr =
	__ATTR(active, 0644, bL_switcher_active_show, bL_switcher_active_store);

static struct kobj_attribute bL_switcher_trace_trigger_attr =
	__ATTR(trace_trigger, 0200, NULL, bL_switcher_trace_trigger_store);

static struct attribute *bL_switcher_attrs[] = {
	&bL_switcher_active_attr.attr,
	&bL_switcher_trace_trigger_attr.attr,
	NULL,
};

static struct attribute_group bL_switcher_attr_group = {
	.attrs = bL_switcher_attrs,
};

static struct kobject *bL_switcher_kobj;

static int __init bL_switcher_sysfs_init(void)
{
	int ret;

	bL_switcher_kobj = kobject_create_and_add("bL_switcher", kernel_kobj);
	if (!bL_switcher_kobj)
		return -ENOMEM;
	ret = sysfs_create_group(bL_switcher_kobj, &bL_switcher_attr_group);
	if (ret)
		kobject_put(bL_switcher_kobj);
	return ret;
}

#endif  /* CONFIG_SYSFS */

bool bL_switcher_get_enabled(void)
{
	mutex_lock(&bL_switcher_activation_lock);

	return bL_switcher_active;
}
EXPORT_SYMBOL_GPL(bL_switcher_get_enabled);

void bL_switcher_put_enabled(void)
{
	mutex_unlock(&bL_switcher_activation_lock);
}
EXPORT_SYMBOL_GPL(bL_switcher_put_enabled);

/*
 * Veto any CPU hotplug operation on those CPUs we've removed
 * while the switcher is active.
 * We're just not ready to deal with that given the trickery involved.
 */
static int bL_switcher_cpu_pre(unsigned int cpu)
{
	int pairing;

	if (!bL_switcher_active)
		return 0;

	pairing = bL_switcher_cpu_pairing[cpu];

	if (pairing == -1)
		return -EINVAL;
	return 0;
}

static bool no_bL_switcher;
core_param(no_bL_switcher, no_bL_switcher, bool, 0644);

static int __init bL_switcher_init(void)
{
	int ret;

	if (!mcpm_is_available())
		return -ENODEV;

	cpuhp_setup_state_nocalls(CPUHP_ARM_BL_PREPARE, "arm/bl:prepare",
				  bL_switcher_cpu_pre, NULL);
	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "arm/bl:predown",
					NULL, bL_switcher_cpu_pre);
	if (ret < 0) {
		cpuhp_remove_state_nocalls(CPUHP_ARM_BL_PREPARE);
		pr_err("bL_switcher: Failed to allocate a hotplug state\n");
		return ret;
	}
	if (!no_bL_switcher) {
		ret = bL_switcher_enable();
		if (ret)
			return ret;
	}

#ifdef CONFIG_SYSFS
	ret = bL_switcher_sysfs_init();
	if (ret)
		pr_err("%s: unable to create sysfs entry\n", __func__);
#endif

	return 0;
}

late_initcall(bL_switcher_init);


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/common/bL_switcher_dummy_if.c -- b.L switcher dummy interface
 *
 * Created by:	Nicolas Pitre, November 2012
 * Copyright:	(C) 2012-2013  Linaro Limited
 *
 * Dummy interface to user space for debugging purpose only.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <asm/bL_switcher.h>

static ssize_t bL_switcher_write(struct file *file, const char __user *buf,
			size_t len, loff_t *pos)
{
	unsigned char val[3];
	unsigned int cpu, cluster;
	int ret;

	pr_debug("%s\n", __func__);

	if (len < 3)
		return -EINVAL;

	if (copy_from_user(val, buf, 3))
		return -EFAULT;

	/* format: <cpu#>,<cluster#> */
	if (val[0] < '0' || val[0] > '9' ||
	    val[1] != ',' ||
	    val[2] < '0' || val[2] > '1')
		return -EINVAL;

	cpu = val[0] - '0';
	cluster = val[2] - '0';
	ret = bL_switch_request(cpu, cluster);

	return ret ? : len;
}

static const struct file_operations bL_switcher_fops = {
	.write		= bL_switcher_write,
	.owner	= THIS_MODULE,
};

static struct miscdevice bL_switcher_device = {
	MISC_DYNAMIC_MINOR,
	"b.L_switcher",
	&bL_switcher_fops
};
module_misc_device(bL_switcher_device);

MODULE_AUTHOR("Nicolas Pitre <nico@linaro.org>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("big.LITTLE switcher dummy user interface");


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2012 Samsung Electronics.
 * Kyungmin Park <kyungmin.park@samsung.com>
 * Tomasz Figa <t.figa@samsung.com>
 */

#include <linux/kernel.h>
#include <linux/suspend.h>

#include <asm/firmware.h>

static const struct firmware_ops default_firmware_ops;

const struct firmware_ops *firmware_ops = &default_firmware_ops;


code:
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, The Linux Foundation. All rights reserved.

#include <linux/spinlock.h>
#include <linux/export.h>

#include <asm/barrier.h>
#include <asm/krait-l2-accessors.h>

static DEFINE_RAW_SPINLOCK(krait_l2_lock);

void krait_set_l2_indirect_reg(u32 addr, u32 val)
{
	unsigned long flags;

	raw_spin_lock_irqsave(&krait_l2_lock, flags);
	/*
	 * Select the L2 window by poking l2cpselr, then write to the window
	 * via l2cpdr.
	 */
	asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
	isb();
	asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val));
	isb();

	raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
}
EXPORT_SYMBOL(krait_set_l2_indirect_reg);

u32 krait_get_l2_indirect_reg(u32 addr)
{
	u32 val;
	unsigned long flags;

	raw_spin_lock_irqsave(&krait_l2_lock, flags);
	/*
	 * Select the L2 window by poking l2cpselr, then read from the window
	 * via l2cpdr.
	 */
	asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
	isb();
	asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val));

	raw_spin_unlock_irqrestore(&krait_l2_lock, flags);

	return val;
}
EXPORT_SYMBOL(krait_get_l2_indirect_reg);


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/common/locomo.c
 *
 * Sharp LoCoMo support
 *
 * This file contains all generic LoCoMo support.
 *
 * All initialization functions provided here are intended to be called
 * from machine specific code with proper arguments when required.
 *
 * Based on sa1111.c
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/io.h>

#include <asm/irq.h>
#include <asm/mach/irq.h>

#include <asm/hardware/locomo.h>

/* LoCoMo Interrupts */
#define IRQ_LOCOMO_KEY		(0)
#define IRQ_LOCOMO_GPIO		(1)
#define IRQ_LOCOMO_LT		(2)
#define IRQ_LOCOMO_SPI		(3)

/* M62332 output channel selection */
#define M62332_EVR_CH	1	/* M62332 volume channel number  */
				/*   0 : CH.1 , 1 : CH. 2        */
/* DAC send data */
#define	M62332_SLAVE_ADDR	0x4e	/* Slave address  */
#define	M62332_W_BIT		0x00	/* W bit (0 only) */
#define	M62332_SUB_ADDR		0x00	/* Sub address    */
#define	M62332_A_BIT		0x00	/* A bit (0 only) */

/* DAC setup and hold times (expressed in us) */
#define DAC_BUS_FREE_TIME	5	/*   4.7 us */
#define DAC_START_SETUP_TIME	5	/*   4.7 us */
#define DAC_STOP_SETUP_TIME	4	/*   4.0 us */
#define DAC_START_HOLD_TIME	5	/*   4.7 us */
#define DAC_SCL_LOW_HOLD_TIME	5	/*   4.7 us */
#define DAC_SCL_HIGH_HOLD_TIME	4	/*   4.0 us */
#define DAC_DATA_SETUP_TIME	1	/*   250 ns */
#define DAC_DATA_HOLD_TIME	1	/*   300 ns */
#define DAC_LOW_SETUP_TIME	1	/*   300 ns */
#define DAC_HIGH_SETUP_TIME	1	/*  1000 ns */

/* the following is the overall data for the locomo chip */
struct locomo {
	struct device *dev;
	unsigned long phys;
	unsigned int irq;
	int irq_base;
	spinlock_t lock;
	void __iomem *base;
#ifdef CONFIG_PM
	void *saved_state;
#endif
};

struct locomo_dev_info {
	unsigned long	offset;
	unsigned long	length;
	unsigned int	devid;
	unsigned int	irq[1];
	const char *	name;
};

/* All the locomo devices.  If offset is non-zero, the mapbase for the
 * locomo_dev will be set to the chip base plus offset.  If offset is
 * zero, then the mapbase for the locomo_dev will be set to zero.  An
 * offset of zero means the device only uses GPIOs or other helper
 * functions inside this file */
static struct locomo_dev_info locomo_devices[] = {
	{
		.devid 		= LOCOMO_DEVID_KEYBOARD,
		.irq		= { IRQ_LOCOMO_KEY },
		.name		= "locomo-keyboard",
		.offset		= LOCOMO_KEYBOARD,
		.length		= 16,
	},
	{
		.devid		= LOCOMO_DEVID_FRONTLIGHT,
		.irq		= {},
		.name		= "locomo-frontlight",
		.offset		= LOCOMO_FRONTLIGHT,
		.length		= 8,

	},
	{
		.devid		= LOCOMO_DEVID_BACKLIGHT,
		.irq		= {},
		.name		= "locomo-backlight",
		.offset		= LOCOMO_BACKLIGHT,
		.length		= 8,
	},
	{
		.devid		= LOCOMO_DEVID_AUDIO,
		.irq		= {},
		.name		= "locomo-audio",
		.offset		= LOCOMO_AUDIO,
		.length		= 4,
	},
	{
		.devid		= LOCOMO_DEVID_LED,
		.irq 		= {},
		.name		= "locomo-led",
		.offset		= LOCOMO_LED,
		.length		= 8,
	},
	{
		.devid		= LOCOMO_DEVID_UART,
		.irq		= {},
		.name		= "locomo-uart",
		.offset		= 0,
		.length		= 0,
	},
	{
		.devid		= LOCOMO_DEVID_SPI,
		.irq		= {},
		.name		= "locomo-spi",
		.offset		= LOCOMO_SPI,
		.length		= 0x30,
	},
};

static void locomo_handler(struct irq_desc *desc)
{
	struct locomo *lchip = irq_desc_get_handler_data(desc);
	int req, i;

	/* Acknowledge the parent IRQ */
	desc->irq_data.chip->irq_ack(&desc->irq_data);

	/* check why this interrupt was generated */
	req = locomo_readl(lchip->base + LOCOMO_ICR) & 0x0f00;

	if (req) {
		unsigned int irq;

		/* generate the next interrupt(s) */
		irq = lchip->irq_base;
		for (i = 0; i <= 3; i++, irq++) {
			if (req & (0x0100 << i)) {
				generic_handle_irq(irq);
			}

		}
	}
}

static void locomo_ack_irq(struct irq_data *d)
{
}

static void locomo_mask_irq(struct irq_data *d)
{
	struct locomo *lchip = irq_data_get_irq_chip_data(d);
	unsigned int r;
	r = locomo_readl(lchip->base + LOCOMO_ICR);
	r &= ~(0x0010 << (d->irq - lchip->irq_base));
	locomo_writel(r, lchip->base + LOCOMO_ICR);
}

static void locomo_unmask_irq(struct irq_data *d)
{
	struct locomo *lchip = irq_data_get_irq_chip_data(d);
	unsigned int r;
	r = locomo_readl(lchip->base + LOCOMO_ICR);
	r |= (0x0010 << (d->irq - lchip->irq_base));
	locomo_writel(r, lchip->base + LOCOMO_ICR);
}

static struct irq_chip locomo_chip = {
	.name		= "LOCOMO",
	.irq_ack	= locomo_ack_irq,
	.irq_mask	= locomo_mask_irq,
	.irq_unmask	= locomo_unmask_irq,
};

static void locomo_setup_irq(struct locomo *lchip)
{
	int irq = lchip->irq_base;

	/*
	 * Install handler for IRQ_LOCOMO_HW.
	 */
	irq_set_irq_type(lchip->irq, IRQ_TYPE_EDGE_FALLING);
	irq_set_chained_handler_and_data(lchip->irq, locomo_handler, lchip);

	/* Install handlers for IRQ_LOCOMO_* */
	for ( ; irq <= lchip->irq_base + 3; irq++) {
		irq_set_chip_and_handler(irq, &locomo_chip, handle_level_irq);
		irq_set_chip_data(irq, lchip);
		irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
	}
}

static void locomo_dev_release(struct device *_dev)
{
	struct locomo_dev *dev = LOCOMO_DEV(_dev);

	kfree(dev);
}

static int
locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info)
{
	struct locomo_dev *dev;
	int ret;

	dev = kzalloc(sizeof(struct locomo_dev), GFP_KERNEL);
	if (!dev) {
		ret = -ENOMEM;
		goto out;
	}

	/*
	 * If the parent device has a DMA mask associated with it,
	 * propagate it down to the children.
	 */
	if (lchip->dev->dma_mask) {
		dev->dma_mask = *lchip->dev->dma_mask;
		dev->dev.dma_mask = &dev->dma_mask;
	}

	dev_set_name(&dev->dev, "%s", info->name);
	dev->devid	 = info->devid;
	dev->dev.parent  = lchip->dev;
	dev->dev.bus     = &locomo_bus_type;
	dev->dev.release = locomo_dev_release;
	dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask;

	if (info->offset)
		dev->mapbase = lchip->base + info->offset;
	else
		dev->mapbase = 0;
	dev->length = info->length;

	dev->irq[0] = (lchip->irq_base == NO_IRQ) ?
			NO_IRQ : lchip->irq_base + info->irq[0];

	ret = device_register(&dev->dev);
	if (ret) {
 out:
		kfree(dev);
	}
	return ret;
}

#ifdef CONFIG_PM

struct locomo_save_data {
	u16	LCM_GPO;
	u16	LCM_SPICT;
	u16	LCM_GPE;
	u16	LCM_ASD;
	u16	LCM_SPIMD;
};

static int locomo_suspend(struct platform_device *dev, pm_message_t state)
{
	struct locomo *lchip = platform_get_drvdata(dev);
	struct locomo_save_data *save;
	unsigned long flags;

	save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL);
	if (!save)
		return -ENOMEM;

	lchip->saved_state = save;

	spin_lock_irqsave(&lchip->lock, flags);

	save->LCM_GPO     = locomo_readl(lchip->base + LOCOMO_GPO);	/* GPIO */
	locomo_writel(0x00, lchip->base + LOCOMO_GPO);
	save->LCM_SPICT   = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPICT);	/* SPI */
	locomo_writel(0x40, lchip->base + LOCOMO_SPI + LOCOMO_SPICT);
	save->LCM_GPE     = locomo_readl(lchip->base + LOCOMO_GPE);	/* GPIO */
	locomo_writel(0x00, lchip->base + LOCOMO_GPE);
	save->LCM_ASD     = locomo_readl(lchip->base + LOCOMO_ASD);	/* ADSTART */
	locomo_writel(0x00, lchip->base + LOCOMO_ASD);
	save->LCM_SPIMD   = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPIMD);	/* SPI */
	locomo_writel(0x3C14, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD);

	locomo_writel(0x00, lchip->base + LOCOMO_PAIF);
	locomo_writel(0x00, lchip->base + LOCOMO_DAC);
	locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC);

	if ((locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88))
		locomo_writel(0x00, lchip->base + LOCOMO_C32K); 	/* CLK32 off */
	else
		/* 18MHz already enabled, so no wait */
		locomo_writel(0xc1, lchip->base + LOCOMO_C32K); 	/* CLK32 on */

	locomo_writel(0x00, lchip->base + LOCOMO_TADC);		/* 18MHz clock off*/
	locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC);			/* 22MHz/24MHz clock off */
	locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);			/* FL */

	spin_unlock_irqrestore(&lchip->lock, flags);

	return 0;
}

static int locomo_resume(struct platform_device *dev)
{
	struct locomo *lchip = platform_get_drvdata(dev);
	struct locomo_save_data *save;
	unsigned long r;
	unsigned long flags;

	save = lchip->saved_state;
	if (!save)
		return 0;

	spin_lock_irqsave(&lchip->lock, flags);

	locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO);
	locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPI + LOCOMO_SPICT);
	locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE);
	locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD);
	locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD);

	locomo_writel(0x00, lchip->base + LOCOMO_C32K);
	locomo_writel(0x90, lchip->base + LOCOMO_TADC);

	locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC);
	r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
	r &= 0xFEFF;
	locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);
	locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);

	spin_unlock_irqrestore(&lchip->lock, flags);

	lchip->saved_state = NULL;
	kfree(save);

	return 0;
}
#endif

/**
 *	locomo_probe - probe for a single LoCoMo chip.
 *	@phys_addr: physical address of device.
 *
 *	Probe for a LoCoMo chip.  This must be called
 *	before any other locomo-specific code.
 *
 *	Returns:
 *	%-ENODEV	device not found.
 *	%-EBUSY		physical address already marked in-use.
 *	%0		successful.
 */
static int
__locomo_probe(struct device *me, struct resource *mem, int irq)
{
	struct locomo_platform_data *pdata = me->platform_data;
	struct locomo *lchip;
	unsigned long r;
	int i, ret = -ENODEV;

	lchip = kzalloc(sizeof(struct locomo), GFP_KERNEL);
	if (!lchip)
		return -ENOMEM;

	spin_lock_init(&lchip->lock);

	lchip->dev = me;
	dev_set_drvdata(lchip->dev, lchip);

	lchip->phys = mem->start;
	lchip->irq = irq;
	lchip->irq_base = (pdata) ? pdata->irq_base : NO_IRQ;

	/*
	 * Map the whole region.  This also maps the
	 * registers for our children.
	 */
	lchip->base = ioremap(mem->start, PAGE_SIZE);
	if (!lchip->base) {
		ret = -ENOMEM;
		goto out;
	}

	/* locomo initialize */
	locomo_writel(0, lchip->base + LOCOMO_ICR);
	/* KEYBOARD */
	locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC);

	/* GPIO */
	locomo_writel(0, lchip->base + LOCOMO_GPO);
	locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14))
			, lchip->base + LOCOMO_GPE);
	locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14))
			, lchip->base + LOCOMO_GPD);
	locomo_writel(0, lchip->base + LOCOMO_GIE);

	/* Frontlight */
	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);

	/* Longtime timer */
	locomo_writel(0, lchip->base + LOCOMO_LTINT);
	/* SPI */
	locomo_writel(0, lchip->base + LOCOMO_SPI + LOCOMO_SPIIE);

	locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD);
	r = locomo_readl(lchip->base + LOCOMO_ASD);
	r |= 0x8000;
	locomo_writel(r, lchip->base + LOCOMO_ASD);

	locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD);
	r = locomo_readl(lchip->base + LOCOMO_HSD);
	r |= 0x8000;
	locomo_writel(r, lchip->base + LOCOMO_HSD);

	locomo_writel(128 / 8, lchip->base + LOCOMO_HSC);

	/* XON */
	locomo_writel(0x80, lchip->base + LOCOMO_TADC);
	udelay(1000);
	/* CLK9MEN */
	r = locomo_readl(lchip->base + LOCOMO_TADC);
	r |= 0x10;
	locomo_writel(r, lchip->base + LOCOMO_TADC);
	udelay(100);

	/* init DAC */
	r = locomo_readl(lchip->base + LOCOMO_DAC);
	r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
	locomo_writel(r, lchip->base + LOCOMO_DAC);

	r = locomo_readl(lchip->base + LOCOMO_VER);
	printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff));

	/*
	 * The interrupt controller must be initialised before any
	 * other device to ensure that the interrupts are available.
	 */
	if (lchip->irq != NO_IRQ && lchip->irq_base != NO_IRQ)
		locomo_setup_irq(lchip);

	for (i = 0; i < ARRAY_SIZE(locomo_devices); i++)
		locomo_init_one_child(lchip, &locomo_devices[i]);
	return 0;

 out:
	kfree(lchip);
	return ret;
}

static int locomo_remove_child(struct device *dev, void *data)
{
	device_unregister(dev);
	return 0;
}

static void __locomo_remove(struct locomo *lchip)
{
	device_for_each_child(lchip->dev, NULL, locomo_remove_child);

	if (lchip->irq != NO_IRQ) {
		irq_set_chained_handler_and_data(lchip->irq, NULL, NULL);
	}

	iounmap(lchip->base);
	kfree(lchip);
}

static int locomo_probe(struct platform_device *dev)
{
	struct resource *mem;
	int irq;

	mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
	if (!mem)
		return -EINVAL;
	irq = platform_get_irq(dev, 0);
	if (irq < 0)
		return -ENXIO;

	return __locomo_probe(&dev->dev, mem, irq);
}

static int locomo_remove(struct platform_device *dev)
{
	struct locomo *lchip = platform_get_drvdata(dev);

	if (lchip) {
		__locomo_remove(lchip);
		platform_set_drvdata(dev, NULL);
	}

	return 0;
}

/*
 *	Not sure if this should be on the system bus or not yet.
 *	We really want some way to register a system device at
 *	the per-machine level, and then have this driver pick
 *	up the registered devices.
 */
static struct platform_driver locomo_device_driver = {
	.probe		= locomo_probe,
	.remove		= locomo_remove,
#ifdef CONFIG_PM
	.suspend	= locomo_suspend,
	.resume		= locomo_resume,
#endif
	.driver		= {
		.name	= "locomo",
	},
};

/*
 *	Get the parent device driver (us) structure
 *	from a child function device
 */
static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev)
{
	return (struct locomo *)dev_get_drvdata(ldev->dev.parent);
}

void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir)
{
	struct locomo *lchip = dev_get_drvdata(dev);
	unsigned long flags;
	unsigned int r;

	if (!lchip)
		return;

	spin_lock_irqsave(&lchip->lock, flags);

	r = locomo_readl(lchip->base + LOCOMO_GPD);
	if (dir)
		r |= bits;
	else
		r &= ~bits;
	locomo_writel(r, lchip->base + LOCOMO_GPD);

	r = locomo_readl(lchip->base + LOCOMO_GPE);
	if (dir)
		r |= bits;
	else
		r &= ~bits;
	locomo_writel(r, lchip->base + LOCOMO_GPE);

	spin_unlock_irqrestore(&lchip->lock, flags);
}
EXPORT_SYMBOL(locomo_gpio_set_dir);

int locomo_gpio_read_level(struct device *dev, unsigned int bits)
{
	struct locomo *lchip = dev_get_drvdata(dev);
	unsigned long flags;
	unsigned int ret;

	if (!lchip)
		return -ENODEV;

	spin_lock_irqsave(&lchip->lock, flags);
	ret = locomo_readl(lchip->base + LOCOMO_GPL);
	spin_unlock_irqrestore(&lchip->lock, flags);

	ret &= bits;
	return ret;
}
EXPORT_SYMBOL(locomo_gpio_read_level);

int locomo_gpio_read_output(struct device *dev, unsigned int bits)
{
	struct locomo *lchip = dev_get_drvdata(dev);
	unsigned long flags;
	unsigned int ret;

	if (!lchip)
		return -ENODEV;

	spin_lock_irqsave(&lchip->lock, flags);
	ret = locomo_readl(lchip->base + LOCOMO_GPO);
	spin_unlock_irqrestore(&lchip->lock, flags);

	ret &= bits;
	return ret;
}
EXPORT_SYMBOL(locomo_gpio_read_output);

void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set)
{
	struct locomo *lchip = dev_get_drvdata(dev);
	unsigned long flags;
	unsigned int r;

	if (!lchip)
		return;

	spin_lock_irqsave(&lchip->lock, flags);

	r = locomo_readl(lchip->base + LOCOMO_GPO);
	if (set)
		r |= bits;
	else
		r &= ~bits;
	locomo_writel(r, lchip->base + LOCOMO_GPO);

	spin_unlock_irqrestore(&lchip->lock, flags);
}
EXPORT_SYMBOL(locomo_gpio_write);

static void locomo_m62332_sendbit(void *mapbase, int bit)
{
	unsigned int r;

	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SCLOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	udelay(DAC_DATA_HOLD_TIME);	/* 300 nsec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SCLOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */

	if (bit & 1) {
		r = locomo_readl(mapbase + LOCOMO_DAC);
		r |=  LOCOMO_DAC_SDAOEB;
		locomo_writel(r, mapbase + LOCOMO_DAC);
		udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	} else {
		r = locomo_readl(mapbase + LOCOMO_DAC);
		r &=  ~(LOCOMO_DAC_SDAOEB);
		locomo_writel(r, mapbase + LOCOMO_DAC);
		udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	}

	udelay(DAC_DATA_SETUP_TIME);	/* 250 nsec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/*  4.0 usec */
}

void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel)
{
	struct locomo *lchip = locomo_chip_driver(ldev);
	int i;
	unsigned char data;
	unsigned int r;
	void *mapbase = lchip->base;
	unsigned long flags;

	spin_lock_irqsave(&lchip->lock, flags);

	/* Start */
	udelay(DAC_BUS_FREE_TIME);	/* 5.0 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.0 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SDAOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_START_HOLD_TIME);	/* 5.0 usec */
	udelay(DAC_DATA_HOLD_TIME);	/* 300 nsec */

	/* Send slave address and W bit (LSB is W bit) */
	data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT;
	for (i = 1; i <= 8; i++) {
		locomo_m62332_sendbit(mapbase, data >> (8 - i));
	}

	/* Check A bit */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SCLOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SDAOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
		printk(KERN_WARNING "locomo: m62332_senddata Error 1\n");
		goto out;
	}

	/* Send Sub address (LSB is channel select) */
	/*    channel = 0 : ch1 select              */
	/*            = 1 : ch2 select              */
	data = M62332_SUB_ADDR + channel;
	for (i = 1; i <= 8; i++) {
		locomo_m62332_sendbit(mapbase, data >> (8 - i));
	}

	/* Check A bit */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SCLOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SDAOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
		printk(KERN_WARNING "locomo: m62332_senddata Error 2\n");
		goto out;
	}

	/* Send DAC data */
	for (i = 1; i <= 8; i++) {
		locomo_m62332_sendbit(mapbase, dac_data >> (8 - i));
	}

	/* Check A bit */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SCLOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SDAOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4.7 usec */
	if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) {	/* High is error */
		printk(KERN_WARNING "locomo: m62332_senddata Error 3\n");
	}

out:
	/* stop */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r &=  ~(LOCOMO_DAC_SCLOEB);
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 300 nsec */
	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4 usec */
	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SDAOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_HIGH_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_HIGH_HOLD_TIME);	/* 4 usec */

	r = locomo_readl(mapbase + LOCOMO_DAC);
	r |=  LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB;
	locomo_writel(r, mapbase + LOCOMO_DAC);
	udelay(DAC_LOW_SETUP_TIME);	/* 1000 nsec */
	udelay(DAC_SCL_LOW_HOLD_TIME);	/* 4.7 usec */

	spin_unlock_irqrestore(&lchip->lock, flags);
}
EXPORT_SYMBOL(locomo_m62332_senddata);

/*
 *	Frontlight control
 */

void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf)
{
	unsigned long flags;
	struct locomo *lchip = locomo_chip_driver(dev);

	if (vr)
		locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 1);
	else
		locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 0);

	spin_lock_irqsave(&lchip->lock, flags);
	locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
	udelay(100);
	locomo_writel(duty, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);
	locomo_writel(bpwf | LOCOMO_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
	spin_unlock_irqrestore(&lchip->lock, flags);
}
EXPORT_SYMBOL(locomo_frontlight_set);

/*
 *	LoCoMo "Register Access Bus."
 *
 *	We model this as a regular bus type, and hang devices directly
 *	off this.
 */
static int locomo_match(struct device *_dev, struct device_driver *_drv)
{
	struct locomo_dev *dev = LOCOMO_DEV(_dev);
	struct locomo_driver *drv = LOCOMO_DRV(_drv);

	return dev->devid == drv->devid;
}

static int locomo_bus_probe(struct device *dev)
{
	struct locomo_dev *ldev = LOCOMO_DEV(dev);
	struct locomo_driver *drv = LOCOMO_DRV(dev->driver);
	int ret = -ENODEV;

	if (drv->probe)
		ret = drv->probe(ldev);
	return ret;
}

static void locomo_bus_remove(struct device *dev)
{
	struct locomo_dev *ldev = LOCOMO_DEV(dev);
	struct locomo_driver *drv = LOCOMO_DRV(dev->driver);

	if (drv->remove)
		drv->remove(ldev);
}

struct bus_type locomo_bus_type = {
	.name		= "locomo-bus",
	.match		= locomo_match,
	.probe		= locomo_bus_probe,
	.remove		= locomo_bus_remove,
};

int locomo_driver_register(struct locomo_driver *driver)
{
	driver->drv.bus = &locomo_bus_type;
	return driver_register(&driver->drv);
}
EXPORT_SYMBOL(locomo_driver_register);

void locomo_driver_unregister(struct locomo_driver *driver)
{
	driver_unregister(&driver->drv);
}
EXPORT_SYMBOL(locomo_driver_unregister);

static int __init locomo_init(void)
{
	int ret = bus_register(&locomo_bus_type);
	if (ret == 0)
		platform_driver_register(&locomo_device_driver);
	return ret;
}

static void __exit locomo_exit(void)
{
	platform_driver_unregister(&locomo_device_driver);
	bus_unregister(&locomo_bus_type);
}

module_init(locomo_init);
module_exit(locomo_exit);

MODULE_DESCRIPTION("Sharp LoCoMo core driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");