diff options
51 files changed, 2291 insertions, 1584 deletions
diff --git a/Documentation/devicetree/bindings/arm/vt8500.txt b/Documentation/devicetree/bindings/arm/vt8500.txt new file mode 100644 index 000000000000..d657832c6819 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vt8500.txt @@ -0,0 +1,14 @@ +VIA/Wondermedia VT8500 Platforms Device Tree Bindings +--------------------------------------- + +Boards with the VIA VT8500 SoC shall have the following properties: +Required root node property: +compatible = "via,vt8500"; + +Boards with the Wondermedia WM8505 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8505"; + +Boards with the Wondermedia WM8650 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8650"; diff --git a/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt new file mode 100644 index 000000000000..0a4ce1051b02 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-intc.txt @@ -0,0 +1,16 @@ +VIA/Wondermedia VT8500 Interrupt Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-intc" +- reg : Should contain 1 register ranges(address and length) +- #interrupt-cells : should be <1> + +Example: + + intc: interrupt-controller@d8140000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + reg = <0xd8140000 0x10000>; + #interrupt-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-pmc.txt b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-pmc.txt new file mode 100644 index 000000000000..521b9c7de933 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-pmc.txt @@ -0,0 +1,13 @@ +VIA/Wondermedia VT8500 Power Management Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-pmc" +- reg : Should contain 1 register ranges(address and length) + +Example: + + pmc@d8130000 { + compatible = "via,vt8500-pmc"; + reg = <0xd8130000 0x1000>; + }; diff --git a/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-timer.txt b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-timer.txt new file mode 100644 index 000000000000..901c73f0d8ef --- /dev/null +++ b/Documentation/devicetree/bindings/arm/vt8500/via,vt8500-timer.txt @@ -0,0 +1,15 @@ +VIA/Wondermedia VT8500 Timer +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-timer" +- reg : Should contain 1 register ranges(address and length) +- interrupts : interrupt for the timer + +Example: + + timer@d8130100 { + compatible = "via,vt8500-timer"; + reg = <0xd8130100 0x28>; + interrupts = <36>; + }; diff --git a/Documentation/devicetree/bindings/clock/vt8500.txt b/Documentation/devicetree/bindings/clock/vt8500.txt new file mode 100644 index 000000000000..a880c70d0047 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/vt8500.txt @@ -0,0 +1,72 @@ +Device Tree Clock bindings for arch-vt8500 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "via,vt8500-pll-clock" - for a VT8500/WM8505 PLL clock + "wm,wm8650-pll-clock" - for a WM8650 PLL clock + "via,vt8500-device-clock" - for a VT/WM device clock + +Required properties for PLL clocks: +- reg : shall be the control register offset from PMC base for the pll clock. +- clocks : shall be the input parent clock phandle for the clock. This should + be the reference clock. +- #clock-cells : from common clock binding; shall be set to 0. + +Required properties for device clocks: +- clocks : shall be the input parent clock phandle for the clock. This should + be a pll output. +- #clock-cells : from common clock binding; shall be set to 0. + + +Device Clocks + +Device clocks are required to have one or both of the following sets of +properties: + + +Gated device clocks: + +Required properties: +- enable-reg : shall be the register offset from PMC base for the enable + register. +- enable-bit : shall be the bit within enable-reg to enable/disable the clock. + + +Divisor device clocks: + +Required property: +- divisor-reg : shall be the register offset from PMC base for the divisor + register. +Optional property: +- divisor-mask : shall be the mask for the divisor register. Defaults to 0x1f + if not specified. + + +For example: + +ref25: ref25M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; +}; + +plla: plla { + #clock-cells = <0>; + compatible = "wm,wm8650-pll-clock"; + clocks = <&ref25>; + reg = <0x200>; +}; + +sdhc: sdhc { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&pllb>; + divisor-reg = <0x328>; + divisor-mask = <0x3f>; + enable-reg = <0x254>; + enable-bit = <18>; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio-vt8500.txt b/Documentation/devicetree/bindings/gpio/gpio-vt8500.txt new file mode 100644 index 000000000000..f4dc5233167e --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-vt8500.txt @@ -0,0 +1,24 @@ +VIA/Wondermedia VT8500 GPIO Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-gpio", "wm,wm8505-gpio" + or "wm,wm8650-gpio" depending on your SoC +- reg : Should contain 1 register range (address and length) +- #gpio-cells : should be <3>. + 1) bank + 2) pin number + 3) flags - should be 0 + +Example: + + gpio: gpio-controller@d8110000 { + compatible = "via,vt8500-gpio"; + gpio-controller; + reg = <0xd8110000 0x10000>; + #gpio-cells = <3>; + }; + + vibrate { + gpios = <&gpio 0 1 0>; /* Bank 0, Pin 1, No flags */ + }; diff --git a/Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt b/Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt new file mode 100644 index 000000000000..3c0484c49582 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt @@ -0,0 +1,15 @@ +VIA/Wondermedia VT8500 Realtime Clock Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-rtc" +- reg : Should contain 1 register ranges(address and length) +- interrupts : alarm interrupt + +Example: + + rtc@d8100000 { + compatible = "via,vt8500-rtc"; + reg = <0xd8100000 0x10000>; + interrupts = <48>; + }; diff --git a/Documentation/devicetree/bindings/tty/serial/via,vt8500-uart.txt b/Documentation/devicetree/bindings/tty/serial/via,vt8500-uart.txt new file mode 100644 index 000000000000..5feef1ef167d --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/via,vt8500-uart.txt @@ -0,0 +1,17 @@ +VIA/Wondermedia VT8500 UART Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-uart" +- reg : Should contain 1 register ranges(address and length) +- interrupts : UART interrupt +- clocks : phandle to the uart source clock (usually a 24Mhz fixed clock) + +Example: + + uart@d8210000 { + compatible = "via,vt8500-uart"; + reg = <0xd8210000 0x1040>; + interrupts = <47>; + clocks = <&ref24>; + }; diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt new file mode 100644 index 000000000000..a4fb0719d157 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/platform-uhci.txt @@ -0,0 +1,15 @@ +Generic Platform UHCI Controller +----------------------------------------------------- + +Required properties: +- compatible : "platform-uhci" +- reg : Should contain 1 register ranges(address and length) +- interrupts : UHCI controller interrupt + +Example: + + uhci@d8007b00 { + compatible = "platform-uhci"; + reg = <0xd8007b00 0x200>; + interrupts = <43>; + }; diff --git a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt new file mode 100644 index 000000000000..17b3ad1d97e7 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt @@ -0,0 +1,15 @@ +VIA/Wondermedia VT8500 EHCI Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-ehci" +- reg : Should contain 1 register ranges(address and length) +- interrupts : ehci controller interrupt + +Example: + + ehci@d8007900 { + compatible = "via,vt8500-ehci"; + reg = <0xd8007900 0x200>; + interrupts = <43>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index db4d3af3643c..5c63da29aa05 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -47,5 +47,7 @@ sirf SiRF Technology, Inc. st STMicroelectronics stericsson ST-Ericsson ti Texas Instruments +via VIA Technologies, Inc. wlf Wolfson Microelectronics +wm Wondermedia Technologies, Inc. xlnx Xilinx diff --git a/Documentation/devicetree/bindings/video/via,vt8500-fb.txt b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt new file mode 100644 index 000000000000..c870b6478ec8 --- /dev/null +++ b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt @@ -0,0 +1,62 @@ +VIA VT8500 Framebuffer +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-fb" +- reg : Should contain 1 register ranges(address and length) +- interrupts : framebuffer controller interrupt +- display: a phandle pointing to the display node + +Required nodes: +- display: a display node is required to initialize the lcd panel + This should be in the board dts. +- default-mode: a videomode within the display with timing parameters + as specified below. + +Example: + + fb@d800e400 { + compatible = "via,vt8500-fb"; + reg = <0xd800e400 0x400>; + interrupts = <12>; + display = <&display>; + default-mode = <&mode0>; + }; + +VIA VT8500 Display +----------------------------------------------------- +Required properties (as per of_videomode_helper): + + - hactive, vactive: Display resolution + - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters + in pixels + vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in + lines + - clock: displayclock in Hz + - bpp: lcd panel bit-depth. + <16> for RGB565, <32> for RGB888 + +Optional properties (as per of_videomode_helper): + - width-mm, height-mm: Display dimensions in mm + - hsync-active-high (bool): Hsync pulse is active high + - vsync-active-high (bool): Vsync pulse is active high + - interlaced (bool): This is an interlaced mode + - doublescan (bool): This is a doublescan mode + +Example: + display: display@0 { + modes { + mode0: mode@0 { + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hfront-porch = <40>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + clock = <0>; /* unused but required */ + bpp = <16>; /* non-standard but required */ + }; + }; + }; diff --git a/Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt b/Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt new file mode 100644 index 000000000000..a850fa011f02 --- /dev/null +++ b/Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt @@ -0,0 +1,13 @@ +VIA/Wondermedia Graphics Engine Controller +----------------------------------------------------- + +Required properties: +- compatible : "wm,prizm-ge-rops" +- reg : Should contain 1 register ranges(address and length) + +Example: + + ge_rops@d8050400 { + compatible = "wm,prizm-ge-rops"; + reg = <0xd8050400 0x100>; + }; diff --git a/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt new file mode 100644 index 000000000000..3d325e1d11ee --- /dev/null +++ b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt @@ -0,0 +1,23 @@ +Wondermedia WM8505 Framebuffer +----------------------------------------------------- + +Required properties: +- compatible : "wm,wm8505-fb" +- reg : Should contain 1 register ranges(address and length) +- via,display: a phandle pointing to the display node + +Required nodes: +- display: a display node is required to initialize the lcd panel + This should be in the board dts. See definition in + Documentation/devicetree/bindings/video/via,vt8500-fb.txt +- default-mode: a videomode node as specified in + Documentation/devicetree/bindings/video/via,vt8500-fb.txt + +Example: + + fb@d8050800 { + compatible = "wm,wm8505-fb"; + reg = <0xd8050800 0x200>; + display = <&display>; + default-mode = <&mode0>; + }; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index de325f4615bd..1fd9bcd25b4d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1004,6 +1004,10 @@ config ARCH_VT8500 select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS select ARCH_REQUIRE_GPIOLIB + select USE_OF + select COMMON_CLK + select HAVE_CLK + select CLKDEV_LOOKUP help Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. @@ -1128,8 +1132,6 @@ source "arch/arm/mach-versatile/Kconfig" source "arch/arm/mach-vexpress/Kconfig" source "arch/arm/plat-versatile/Kconfig" -source "arch/arm/mach-vt8500/Kconfig" - source "arch/arm/mach-w90x900/Kconfig" # Definitions to make life easier @@ -1622,6 +1624,7 @@ config ARCH_NR_GPIO default 355 if ARCH_U8500 default 264 if MACH_H4700 default 512 if SOC_OMAP5 + default 288 if ARCH_VT8500 default 0 help Maximum number of GPIOs in the system. diff --git a/arch/arm/boot/dts/vt8500-bv07.dts b/arch/arm/boot/dts/vt8500-bv07.dts new file mode 100644 index 000000000000..567cf4e8ab84 --- /dev/null +++ b/arch/arm/boot/dts/vt8500-bv07.dts @@ -0,0 +1,36 @@ +/* + * vt8500-bv07.dts - Device tree file for Benign BV07 Netbook + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Licensed under GPLv2 or later + */ + +/dts-v1/; +/include/ "vt8500.dtsi" + +/ { + model = "Benign BV07 Netbook"; + + /* + * Display node is based on Sascha Hauer's patch on dri-devel. + * Added a bpp property to calculate the size of the framebuffer + * until the binding is formalized. + */ + display: display@0 { + modes { + mode0: mode@0 { + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hfront-porch = <40>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + clock = <0>; /* unused but required */ + bpp = <16>; /* non-standard but required */ + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/vt8500.dtsi b/arch/arm/boot/dts/vt8500.dtsi new file mode 100644 index 000000000000..d8645e990b21 --- /dev/null +++ b/arch/arm/boot/dts/vt8500.dtsi @@ -0,0 +1,116 @@ +/* + * vt8500.dtsi - Device tree file for VIA VT8500 SoC + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Licensed under GPLv2 or later + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "via,vt8500"; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + interrupt-parent = <&intc>; + + intc: interrupt-controller@d8140000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + reg = <0xd8140000 0x10000>; + #interrupt-cells = <1>; + }; + + gpio: gpio-controller@d8110000 { + compatible = "via,vt8500-gpio"; + gpio-controller; + reg = <0xd8110000 0x10000>; + #gpio-cells = <3>; + }; + + pmc@d8130000 { + compatible = "via,vt8500-pmc"; + reg = <0xd8130000 0x1000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ref24: ref24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + }; + + timer@d8130100 { + compatible = "via,vt8500-timer"; + reg = <0xd8130100 0x28>; + interrupts = <36>; + }; + + ehci@d8007900 { + compatible = "via,vt8500-ehci"; + reg = <0xd8007900 0x200>; + interrupts = <43>; + }; + + uhci@d8007b00 { + compatible = "platform-uhci"; + reg = <0xd8007b00 0x200>; + interrupts = <43>; + }; + + fb@d800e400 { + compatible = "via,vt8500-fb"; + reg = <0xd800e400 0x400>; + interrupts = <12>; + display = <&display>; + default-mode = <&mode0>; + }; + + ge_rops@d8050400 { + compatible = "wm,prizm-ge-rops"; + reg = <0xd8050400 0x100>; + }; + + uart@d8200000 { + compatible = "via,vt8500-uart"; + reg = <0xd8200000 0x1040>; + interrupts = <32>; + clocks = <&ref24>; + }; + + uart@d82b0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82b0000 0x1040>; + interrupts = <33>; + clocks = <&ref24>; + }; + + uart@d8210000 { + compatible = "via,vt8500-uart"; + reg = <0xd8210000 0x1040>; + interrupts = <47>; + clocks = <&ref24>; + }; + + uart@d82c0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82c0000 0x1040>; + interrupts = <50>; + clocks = <&ref24>; + }; + + rtc@d8100000 { + compatible = "via,vt8500-rtc"; + reg = <0xd8100000 0x10000>; + interrupts = <48>; + }; + }; +}; diff --git a/arch/arm/boot/dts/wm8505-ref.dts b/arch/arm/boot/dts/wm8505-ref.dts new file mode 100644 index 000000000000..fd4e248074c6 --- /dev/null +++ b/arch/arm/boot/dts/wm8505-ref.dts @@ -0,0 +1,36 @@ +/* + * wm8505-ref.dts - Device tree file for Wondermedia WM8505 reference netbook + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Licensed under GPLv2 or later + */ + +/dts-v1/; +/include/ "wm8505.dtsi" + +/ { + model = "Wondermedia WM8505 Netbook"; + + /* + * Display node is based on Sascha Hauer's patch on dri-devel. + * Added a bpp property to calculate the size of the framebuffer + * until the binding is formalized. + */ + display: display@0 { + modes { + mode0: mode@0 { + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hfront-porch = <40>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + clock = <0>; /* unused but required */ + bpp = <32>; /* non-standard but required */ + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/wm8505.dtsi b/arch/arm/boot/dts/wm8505.dtsi new file mode 100644 index 000000000000..b459691655ab --- /dev/null +++ b/arch/arm/boot/dts/wm8505.dtsi @@ -0,0 +1,143 @@ +/* + * wm8505.dtsi - Device tree file for Wondermedia WM8505 SoC + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Licensed under GPLv2 or later + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "wm,wm8505"; + + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + interrupt-parent = <&intc0>; + + intc0: interrupt-controller@d8140000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + reg = <0xd8140000 0x10000>; + #interrupt-cells = <1>; + }; + + /* Secondary IC cascaded to intc0 */ + intc1: interrupt-controller@d8150000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xD8150000 0x10000>; + interrupts = <56 57 58 59 60 61 62 63>; + }; + + gpio: gpio-controller@d8110000 { + compatible = "wm,wm8505-gpio"; + gpio-controller; + reg = <0xd8110000 0x10000>; + #gpio-cells = <3>; + }; + + pmc@d8130000 { + compatible = "via,vt8500-pmc"; + reg = <0xd8130000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ref24: ref24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + }; + }; + + timer@d8130100 { + compatible = "via,vt8500-timer"; + reg = <0xd8130100 0x28>; + interrupts = <36>; + }; + + ehci@d8007100 { + compatible = "via,vt8500-ehci"; + reg = <0xd8007100 0x200>; + interrupts = <43>; + }; + + uhci@d8007300 { + compatible = "platform-uhci"; + reg = <0xd8007300 0x200>; + interrupts = <43>; + }; + + fb@d8050800 { + compatible = "wm,wm8505-fb"; + reg = <0xd8050800 0x200>; + display = <&display>; + default-mode = <&mode0>; + }; + + ge_rops@d8050400 { + compatible = "wm,prizm-ge-rops"; + reg = <0xd8050400 0x100>; + }; + + uart@d8200000 { + compatible = "via,vt8500-uart"; + reg = <0xd8200000 0x1040>; + interrupts = <32>; + clocks = <&ref24>; + }; + + uart@d82b0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82b0000 0x1040>; + interrupts = <33>; + clocks = <&ref24>; + }; + + uart@d8210000 { + compatible = "via,vt8500-uart"; + reg = <0xd8210000 0x1040>; + interrupts = <47>; + clocks = <&ref24>; + }; + + uart@d82c0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82c0000 0x1040>; + interrupts = <50>; + clocks = <&ref24>; + }; + + uart@d8370000 { + compatible = "via,vt8500-uart"; + reg = <0xd8370000 0x1040>; + interrupts = <31>; + clocks = <&ref24>; + }; + + uart@d8380000 { + compatible = "via,vt8500-uart"; + reg = <0xd8380000 0x1040>; + interrupts = <30>; + clocks = <&ref24>; + }; + + rtc@d8100000 { + compatible = "via,vt8500-rtc"; + reg = <0xd8100000 0x10000>; + interrupts = <48>; + }; + }; +}; diff --git a/arch/arm/boot/dts/wm8650-mid.dts b/arch/arm/boot/dts/wm8650-mid.dts new file mode 100644 index 000000000000..cefd938f842f --- /dev/null +++ b/arch/arm/boot/dts/wm8650-mid.dts @@ -0,0 +1,36 @@ +/* + * wm8650-mid.dts - Device tree file for Wondermedia WM8650-MID Tablet + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Licensed under GPLv2 or later + */ + +/dts-v1/; +/include/ "wm8650.dtsi" + +/ { + model = "Wondermedia WM8650-MID Tablet"; + + /* + * Display node is based on Sascha Hauer's patch on dri-devel. + * Added a bpp property to calculate the size of the framebuffer + * until the binding is formalized. + */ + display: display@0 { + modes { + mode0: mode@0 { + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hfront-porch = <40>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + clock = <0>; /* unused but required */ + bpp = <16>; /* non-standard but required */ + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi new file mode 100644 index 000000000000..83b9467559bb --- /dev/null +++ b/arch/arm/boot/dts/wm8650.dtsi @@ -0,0 +1,147 @@ +/* + * wm8650.dtsi - Device tree file for Wondermedia WM8650 SoC + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Licensed under GPLv2 or later + */ + +/include/ "skeleton.dtsi" + +/ { + compatible = "wm,wm8650"; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + interrupt-parent = <&intc0>; + + intc0: interrupt-controller@d8140000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + reg = <0xd8140000 0x10000>; + #interrupt-cells = <1>; + }; + + /* Secondary IC cascaded to intc0 */ + intc1: interrupt-controller@d8150000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xD8150000 0x10000>; + interrupts = <56 57 58 59 60 61 62 63>; + }; + + gpio: gpio-controller@d8110000 { + compatible = "wm,wm8650-gpio"; + gpio-controller; + reg = <0xd8110000 0x10000>; + #gpio-cells = <3>; + }; + + pmc@d8130000 { + compatible = "via,vt8500-pmc"; + reg = <0xd8130000 0x1000>; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + ref25: ref25M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + ref24: ref24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + plla: plla { + #clock-cells = <0>; + compatible = "wm,wm8650-pll-clock"; + clocks = <&ref25>; + reg = <0x200>; + }; + + pllb: pllb { + #clock-cells = <0>; + compatible = "wm,wm8650-pll-clock"; + clocks = <&ref25>; + reg = <0x204>; + }; + + arm: arm { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&plla>; + divisor-reg = <0x300>; + }; + + sdhc: sdhc { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&pllb>; + divisor-reg = <0x328>; + divisor-mask = <0x3f>; + enable-reg = <0x254>; + enable-bit = <18>; + }; + }; + }; + + timer@d8130100 { + compatible = "via,vt8500-timer"; + reg = <0xd8130100 0x28>; + interrupts = <36>; + }; + + ehci@d8007900 { + compatible = "via,vt8500-ehci"; + reg = <0xd8007900 0x200>; + interrupts = <43>; + }; + + uhci@d8007b00 { + compatible = "platform-uhci"; + reg = <0xd8007b00 0x200>; + interrupts = <43>; + }; + + fb@d8050800 { + compatible = "wm,wm8505-fb"; + reg = <0xd8050800 0x200>; + display = <&display>; + default-mode = <&mode0>; + }; + + ge_rops@d8050400 { + compatible = "wm,prizm-ge-rops"; + reg = <0xd8050400 0x100>; + }; + + uart@d8200000 { + compatible = "via,vt8500-uart"; + reg = <0xd8200000 0x1040>; + interrupts = <32>; + clocks = <&ref24>; + }; + + uart@d82b0000 { + compatible = "via,vt8500-uart"; + reg = <0xd82b0000 0x1040>; + interrupts = <33>; + clocks = <&ref24>; + }; + + rtc@d8100000 { + compatible = "via,vt8500-rtc"; + reg = <0xd8100000 0x10000>; + interrupts = <48>; + }; + }; +}; diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig deleted file mode 100644 index 2c20a341c11a..000000000000 --- a/arch/arm/mach-vt8500/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -if ARCH_VT8500 - -config VTWM_VERSION_VT8500 - bool - -config VTWM_VERSION_WM8505 - bool - -config MACH_BV07 - bool "Benign BV07-8500 Mini Netbook" - depends on ARCH_VT8500 - select VTWM_VERSION_VT8500 - help - Add support for the inexpensive 7-inch netbooks sold by many - Chinese distributors under various names. Note that there are - many hardware implementations in identical exterior, make sure - that yours is indeed based on a VIA VT8500 chip. - -config MACH_WM8505_7IN_NETBOOK - bool "WM8505 7-inch generic netbook" - depends on ARCH_VT8500 - select VTWM_VERSION_WM8505 - help - Add support for the inexpensive 7-inch netbooks sold by many - Chinese distributors under various names. Note that there are - many hardware implementations in identical exterior, make sure - that yours is indeed based on a WonderMedia WM8505 chip. - -comment "LCD panel size" - -config WMT_PANEL_800X480 - bool "7-inch with 800x480 resolution" - depends on (FB_VT8500 || FB_WM8505) - default y - help - These are found in most of the netbooks in generic cases, as - well as in Eken M001 tablets and possibly elsewhere. - - To select this panel at runtime, say y here and append - 'panel=800x480' to your kernel command line. Otherwise, the - largest one available will be used. - -config WMT_PANEL_800X600 - bool "8-inch with 800x600 resolution" - depends on (FB_VT8500 || FB_WM8505) - help - These are found in Eken M003 tablets and possibly elsewhere. - - To select this panel at runtime, say y here and append - 'panel=800x600' to your kernel command line. Otherwise, the - largest one available will be used. - -config WMT_PANEL_1024X576 - bool "10-inch with 1024x576 resolution" - depends on (FB_VT8500 || FB_WM8505) - help - These are found in CherryPal netbooks and possibly elsewhere. - - To select this panel at runtime, say y here and append - 'panel=1024x576' to your kernel command line. Otherwise, the - largest one available will be used. - -config WMT_PANEL_1024X600 - bool "10-inch with 1024x600 resolution" - depends on (FB_VT8500 || FB_WM8505) - help - These are found in Eken M006 tablets and possibly elsewhere. - - To select this panel at runtime, say y here and append - 'panel=1024x600' to your kernel command line. Otherwise, the - largest one available will be used. - -endif diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile index 7ce51767c99c..e035251cda48 100644 --- a/arch/arm/mach-vt8500/Makefile +++ b/arch/arm/mach-vt8500/Makefile @@ -1,7 +1 @@ -obj-y += devices.o gpio.o irq.o timer.o restart.o - -obj-$(CONFIG_VTWM_VERSION_VT8500) += devices-vt8500.o -obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o - -obj-$(CONFIG_MACH_BV07) += bv07.o -obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o +obj-$(CONFIG_ARCH_VT8500) += irq.o timer.o vt8500.o diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c deleted file mode 100644 index f9fbeb2d10e9..000000000000 --- a/arch/arm/mach-vt8500/bv07.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * arch/arm/mach-vt8500/bv07.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/io.h> -#include <linux/pm.h> - -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <mach/restart.h> - -#include "devices.h" - -static void __iomem *pmc_hiber; - -static struct platform_device *devices[] __initdata = { - &vt8500_device_uart0, - &vt8500_device_lcdc, - &vt8500_device_ehci, - &vt8500_device_ge_rops, - &vt8500_device_pwm, - &vt8500_device_pwmbl, - &vt8500_device_rtc, -}; - -static void vt8500_power_off(void) -{ - local_irq_disable(); - writew(5, pmc_hiber); - asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0)); -} - -void __init bv07_init(void) -{ -#ifdef CONFIG_FB_VT8500 - void __iomem *gpio_mux_reg = ioremap(wmt_gpio_base + 0x200, 4); - if (gpio_mux_reg) { - writel(readl(gpio_mux_reg) | 1, gpio_mux_reg); - iounmap(gpio_mux_reg); - } else { - printk(KERN_ERR "Could not remap the GPIO mux register, display may not work properly!\n"); - } -#endif - pmc_hiber = ioremap(wmt_pmc_base + 0x12, 2); - if (pmc_hiber) - pm_power_off = &vt8500_power_off; - else - printk(KERN_ERR "PMC Hibernation register could not be remapped, not enabling power off!\n"); - - wmt_setup_restart(); - vt8500_set_resources(); - platform_add_devices(devices, ARRAY_SIZE(devices)); - vt8500_gpio_init(); -} - -MACHINE_START(BV07, "Benign BV07 Mini Netbook") - .atag_offset = 0x100, - .restart = wmt_restart, - .reserve = vt8500_reserve_mem, - .map_io = vt8500_map_io, - .init_irq = vt8500_init_irq, - .timer = &vt8500_timer, - .init_machine = bv07_init, -MACHINE_END diff --git a/arch/arm/mach-vt8500/common.h b/arch/arm/mach-vt8500/common.h new file mode 100644 index 000000000000..2b2419646e95 --- /dev/null +++ b/arch/arm/mach-vt8500/common.h @@ -0,0 +1,28 @@ +/* linux/arch/arm/mach-vt8500/dt_common.h + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ARCH_ARM_MACH_VT8500_DT_COMMON_H +#define __ARCH_ARM_MACH_VT8500_DT_COMMON_H + +#include <linux/of.h> + +void __init vt8500_timer_init(void); +int __init vt8500_irq_init(struct device_node *node, + struct device_node *parent); + +/* defined in drivers/clk/clk-vt8500.c */ +void __init vtwm_clk_init(void __iomem *pmc_base); + +#endif diff --git a/arch/arm/mach-vt8500/devices-vt8500.c b/arch/arm/mach-vt8500/devices-vt8500.c deleted file mode 100644 index 19519aeecf37..000000000000 --- a/arch/arm/mach-vt8500/devices-vt8500.c +++ /dev/null @@ -1,91 +0,0 @@ -/* linux/arch/arm/mach-vt8500/devices-vt8500.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/platform_device.h> - -#include <mach/vt8500_regs.h> -#include <mach/vt8500_irqs.h> -#include <mach/i8042.h> -#include "devices.h" - -void __init vt8500_set_resources(void) -{ - struct resource tmp[3]; - - tmp[0] = wmt_mmio_res(VT8500_LCDC_BASE, SZ_1K); - tmp[1] = wmt_irq_res(IRQ_LCDC); - wmt_res_add(&vt8500_device_lcdc, tmp, 2); - - tmp[0] = wmt_mmio_res(VT8500_UART0_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART0); - wmt_res_add(&vt8500_device_uart0, tmp, 2); - - tmp[0] = wmt_mmio_res(VT8500_UART1_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART1); - wmt_res_add(&vt8500_device_uart1, tmp, 2); - - tmp[0] = wmt_mmio_res(VT8500_UART2_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART2); - wmt_res_add(&vt8500_device_uart2, tmp, 2); - - tmp[0] = wmt_mmio_res(VT8500_UART3_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART3); - wmt_res_add(&vt8500_device_uart3, tmp, 2); - - tmp[0] = wmt_mmio_res(VT8500_EHCI_BASE, SZ_512); - tmp[1] = wmt_irq_res(IRQ_EHCI); - wmt_res_add(&vt8500_device_ehci, tmp, 2); - - tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256); - wmt_res_add(&vt8500_device_ge_rops, tmp, 1); - - tmp[0] = wmt_mmio_res(VT8500_PWM_BASE, 0x44); - wmt_res_add(&vt8500_device_pwm, tmp, 1); - - tmp[0] = wmt_mmio_res(VT8500_RTC_BASE, 0x2c); - tmp[1] = wmt_irq_res(IRQ_RTC); - tmp[2] = wmt_irq_res(IRQ_RTCSM); - wmt_res_add(&vt8500_device_rtc, tmp, 3); -} - -static void __init vt8500_set_externs(void) -{ - /* Non-resource-aware stuff */ - wmt_ic_base = VT8500_IC_BASE; - wmt_gpio_base = VT8500_GPIO_BASE; - wmt_pmc_base = VT8500_PMC_BASE; - wmt_i8042_base = VT8500_PS2_BASE; - - wmt_nr_irqs = VT8500_NR_IRQS; - wmt_timer_irq = IRQ_PMCOS0; - wmt_gpio_ext_irq[0] = IRQ_EXT0; - wmt_gpio_ext_irq[1] = IRQ_EXT1; - wmt_gpio_ext_irq[2] = IRQ_EXT2; - wmt_gpio_ext_irq[3] = IRQ_EXT3; - wmt_gpio_ext_irq[4] = IRQ_EXT4; - wmt_gpio_ext_irq[5] = IRQ_EXT5; - wmt_gpio_ext_irq[6] = IRQ_EXT6; - wmt_gpio_ext_irq[7] = IRQ_EXT7; - wmt_i8042_kbd_irq = IRQ_PS2KBD; - wmt_i8042_aux_irq = IRQ_PS2MOUSE; -} - -void __init vt8500_map_io(void) -{ - iotable_init(wmt_io_desc, ARRAY_SIZE(wmt_io_desc)); - - /* Should be done before interrupts and timers are initialized */ - vt8500_set_externs(); -} diff --git a/arch/arm/mach-vt8500/devices-wm8505.c b/arch/arm/mach-vt8500/devices-wm8505.c deleted file mode 100644 index db4594e029f4..000000000000 --- a/arch/arm/mach-vt8500/devices-wm8505.c +++ /dev/null @@ -1,99 +0,0 @@ -/* linux/arch/arm/mach-vt8500/devices-wm8505.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/platform_device.h> - -#include <mach/wm8505_regs.h> -#include <mach/wm8505_irqs.h> -#include <mach/i8042.h> -#include "devices.h" - -void __init wm8505_set_resources(void) -{ - struct resource tmp[3]; - - tmp[0] = wmt_mmio_res(WM8505_GOVR_BASE, SZ_512); - wmt_res_add(&vt8500_device_wm8505_fb, tmp, 1); - - tmp[0] = wmt_mmio_res(WM8505_UART0_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART0); - wmt_res_add(&vt8500_device_uart0, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_UART1_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART1); - wmt_res_add(&vt8500_device_uart1, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_UART2_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART2); - wmt_res_add(&vt8500_device_uart2, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_UART3_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART3); - wmt_res_add(&vt8500_device_uart3, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_UART4_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART4); - wmt_res_add(&vt8500_device_uart4, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_UART5_BASE, 0x1040); - tmp[1] = wmt_irq_res(IRQ_UART5); - wmt_res_add(&vt8500_device_uart5, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_EHCI_BASE, SZ_512); - tmp[1] = wmt_irq_res(IRQ_EHCI); - wmt_res_add(&vt8500_device_ehci, tmp, 2); - - tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256); - wmt_res_add(&vt8500_device_ge_rops, tmp, 1); - - tmp[0] = wmt_mmio_res(WM8505_PWM_BASE, 0x44); - wmt_res_add(&vt8500_device_pwm, tmp, 1); - - tmp[0] = wmt_mmio_res(WM8505_RTC_BASE, 0x2c); - tmp[1] = wmt_irq_res(IRQ_RTC); - tmp[2] = wmt_irq_res(IRQ_RTCSM); - wmt_res_add(&vt8500_device_rtc, tmp, 3); -} - -static void __init wm8505_set_externs(void) -{ - /* Non-resource-aware stuff */ - wmt_ic_base = WM8505_IC_BASE; - wmt_sic_base = WM8505_SIC_BASE; - wmt_gpio_base = WM8505_GPIO_BASE; - wmt_pmc_base = WM8505_PMC_BASE; - wmt_i8042_base = WM8505_PS2_BASE; - - wmt_nr_irqs = WM8505_NR_IRQS; - wmt_timer_irq = IRQ_PMCOS0; - wmt_gpio_ext_irq[0] = IRQ_EXT0; - wmt_gpio_ext_irq[1] = IRQ_EXT1; - wmt_gpio_ext_irq[2] = IRQ_EXT2; - wmt_gpio_ext_irq[3] = IRQ_EXT3; - wmt_gpio_ext_irq[4] = IRQ_EXT4; - wmt_gpio_ext_irq[5] = IRQ_EXT5; - wmt_gpio_ext_irq[6] = IRQ_EXT6; - wmt_gpio_ext_irq[7] = IRQ_EXT7; - wmt_i8042_kbd_irq = IRQ_PS2KBD; - wmt_i8042_aux_irq = IRQ_PS2MOUSE; -} - -void __init wm8505_map_io(void) -{ - iotable_init(wmt_io_desc, ARRAY_SIZE(wmt_io_desc)); - - /* Should be done before interrupts and timers are initialized */ - wm8505_set_externs(); -} diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c deleted file mode 100644 index 1fcdc36b358d..000000000000 --- a/arch/arm/mach-vt8500/devices.c +++ /dev/null @@ -1,270 +0,0 @@ -/* linux/arch/arm/mach-vt8500/devices.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/io.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#include <linux/pwm_backlight.h> -#include <linux/memblock.h> - -#include <asm/mach/arch.h> - -#include <mach/vt8500fb.h> -#include <mach/i8042.h> -#include "devices.h" - -/* These can't use resources currently */ -unsigned long wmt_ic_base __initdata; -unsigned long wmt_sic_base __initdata; -unsigned long wmt_gpio_base __initdata; -unsigned long wmt_pmc_base __initdata; -unsigned long wmt_i8042_base __initdata; - -int wmt_nr_irqs __initdata; -int wmt_timer_irq __initdata; -int wmt_gpio_ext_irq[8] __initdata; - -/* Should remain accessible after init. - * i8042 driver desperately calls for attention... - */ -int wmt_i8042_kbd_irq; -int wmt_i8042_aux_irq; - -static u64 fb_dma_mask = DMA_BIT_MASK(32); - -struct platform_device vt8500_device_lcdc = { - .name = "vt8500-lcd", - .id = 0, - .dev = { - .dma_mask = &fb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -struct platform_device vt8500_device_wm8505_fb = { - .name = "wm8505-fb", - .id = 0, -}; - -/* Smallest to largest */ -static struct vt8500fb_platform_data panels[] = { -#ifdef CONFIG_WMT_PANEL_800X480 -{ - .xres_virtual = 800, - .yres_virtual = 480 * 2, - .mode = { - .name = "800x480", - .xres = 800, - .yres = 480, - .left_margin = 88, - .right_margin = 40, - .upper_margin = 32, - .lower_margin = 11, - .hsync_len = 0, - .vsync_len = 1, - .vmode = FB_VMODE_NONINTERLACED, - }, -}, -#endif -#ifdef CONFIG_WMT_PANEL_800X600 -{ - .xres_virtual = 800, - .yres_virtual = 600 * 2, - .mode = { - .name = "800x600", - .xres = 800, - .yres = 600, - .left_margin = 88, - .right_margin = 40, - .upper_margin = 32, - .lower_margin = 11, - .hsync_len = 0, - .vsync_len = 1, - .vmode = FB_VMODE_NONINTERLACED, - }, -}, -#endif -#ifdef CONFIG_WMT_PANEL_1024X576 -{ - .xres_virtual = 1024, - .yres_virtual = 576 * 2, - .mode = { - .name = "1024x576", - .xres = 1024, - .yres = 576, - .left_margin = 40, - .right_margin = 24, - .upper_margin = 32, - .lower_margin = 11, - .hsync_len = 96, - .vsync_len = 2, - .vmode = FB_VMODE_NONINTERLACED, - }, -}, -#endif -#ifdef CONFIG_WMT_PANEL_1024X600 -{ - .xres_virtual = 1024, - .yres_virtual = 600 * 2, - .mode = { - .name = "1024x600", - .xres = 1024, - .yres = 600, - .left_margin = 66, - .right_margin = 2, - .upper_margin = 19, - .lower_margin = 1, - .hsync_len = 23, - .vsync_len = 8, - .vmode = FB_VMODE_NONINTERLACED, - }, -}, -#endif -}; - -static int current_panel_idx __initdata = ARRAY_SIZE(panels) - 1; - -static int __init panel_setup(char *str) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(panels); i++) { - if (strcmp(panels[i].mode.name, str) == 0) { - current_panel_idx = i; - break; - } - } - return 0; -} - -early_param("panel", panel_setup); - -static inline void preallocate_fb(struct vt8500fb_platform_data *p, - unsigned long align) { - p->video_mem_len = (p->xres_virtual * p->yres_virtual * 4) >> - (p->bpp > 16 ? 0 : (p->bpp > 8 ? 1 : - (8 / p->bpp) + 1)); - p->video_mem_phys = (unsigned long)memblock_alloc(p->video_mem_len, - align); - p->video_mem_virt = phys_to_virt(p->video_mem_phys); -} - -struct platform_device vt8500_device_uart0 = { - .name = "vt8500_serial", - .id = 0, -}; - -struct platform_device vt8500_device_uart1 = { - .name = "vt8500_serial", - .id = 1, -}; - -struct platform_device vt8500_device_uart2 = { - .name = "vt8500_serial", - .id = 2, -}; - -struct platform_device vt8500_device_uart3 = { - .name = "vt8500_serial", - .id = 3, -}; - -struct platform_device vt8500_device_uart4 = { - .name = "vt8500_serial", - .id = 4, -}; - -struct platform_device vt8500_device_uart5 = { - .name = "vt8500_serial", - .id = 5, -}; - -static u64 ehci_dma_mask = DMA_BIT_MASK(32); - -struct platform_device vt8500_device_ehci = { - .name = "vt8500-ehci", - .id = 0, - .dev = { - .dma_mask = &ehci_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -struct platform_device vt8500_device_ge_rops = { - .name = "wmt_ge_rops", - .id = -1, -}; - -struct platform_device vt8500_device_pwm = { - .name = "vt8500-pwm", - .id = 0, -}; - -static struct platform_pwm_backlight_data vt8500_pwmbl_data = { - .pwm_id = 0, - .max_brightness = 128, - .dft_brightness = 70, - .pwm_period_ns = 250000, /* revisit when clocks are implemented */ -}; - -struct platform_device vt8500_device_pwmbl = { - .name = "pwm-backlight", - .id = 0, - .dev = { - .platform_data = &vt8500_pwmbl_data, - }, -}; - -struct platform_device vt8500_device_rtc = { - .name = "vt8500-rtc", - .id = 0, -}; - -struct map_desc wmt_io_desc[] __initdata = { - /* SoC MMIO registers */ - [0] = { - .virtual = 0xf8000000, - .pfn = __phys_to_pfn(0xd8000000), - .length = 0x00390000, /* max of all chip variants */ - .type = MT_DEVICE - }, - /* PCI I/O space, numbers tied to those in <mach/io.h> */ - [1] = { - .virtual = 0xf0000000, - .pfn = __phys_to_pfn(0xc0000000), - .length = SZ_64K, - .type = MT_DEVICE - }, -}; - -void __init vt8500_reserve_mem(void) -{ -#ifdef CONFIG_FB_VT8500 - panels[current_panel_idx].bpp = 16; /* Always use RGB565 */ - preallocate_fb(&panels[current_panel_idx], SZ_4M); - vt8500_device_lcdc.dev.platform_data = &panels[current_panel_idx]; -#endif -} - -void __init wm8505_reserve_mem(void) -{ -#if defined CONFIG_FB_WM8505 - panels[current_panel_idx].bpp = 32; /* Always use RGB888 */ - preallocate_fb(&panels[current_panel_idx], 32); - vt8500_device_wm8505_fb.dev.platform_data = &panels[current_panel_idx]; -#endif -} diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h deleted file mode 100644 index 188d4e17f35c..000000000000 --- a/arch/arm/mach-vt8500/devices.h +++ /dev/null @@ -1,88 +0,0 @@ -/* linux/arch/arm/mach-vt8500/devices.h - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ARCH_ARM_MACH_VT8500_DEVICES_H -#define __ARCH_ARM_MACH_VT8500_DEVICES_H - -#include <linux/platform_device.h> -#include <asm/mach/map.h> - -void __init vt8500_init_irq(void); -void __init wm8505_init_irq(void); -void __init vt8500_map_io(void); -void __init wm8505_map_io(void); -void __init vt8500_reserve_mem(void); -void __init wm8505_reserve_mem(void); -void __init vt8500_gpio_init(void); -void __init vt8500_set_resources(void); -void __init wm8505_set_resources(void); - -extern unsigned long wmt_ic_base __initdata; -extern unsigned long wmt_sic_base __initdata; -extern unsigned long wmt_gpio_base __initdata; -extern unsigned long wmt_pmc_base __initdata; - -extern int wmt_nr_irqs __initdata; -extern int wmt_timer_irq __initdata; -extern int wmt_gpio_ext_irq[8] __initdata; - -extern struct map_desc wmt_io_desc[2] __initdata; - -static inline struct resource wmt_mmio_res(u32 start, u32 size) -{ - struct resource tmp = { - .flags = IORESOURCE_MEM, - .start = start, - .end = start + size - 1, - }; - - return tmp; -} - -static inline struct resource wmt_irq_res(int irq) -{ - struct resource tmp = { - .flags = IORESOURCE_IRQ, - .start = irq, - .end = irq, - }; - - return tmp; -} - -static inline void wmt_res_add(struct platform_device *pdev, - const struct resource *res, unsigned int num) -{ - if (unlikely(platform_device_add_resources(pdev, res, num))) - pr_err("Failed to assign resources\n"); -} - -extern struct sys_timer vt8500_timer; - -extern struct platform_device vt8500_device_uart0; -extern struct platform_device vt8500_device_uart1; -extern struct platform_device vt8500_device_uart2; -extern struct platform_device vt8500_device_uart3; -extern struct platform_device vt8500_device_uart4; -extern struct platform_device vt8500_device_uart5; - -extern struct platform_device vt8500_device_lcdc; -extern struct platform_device vt8500_device_wm8505_fb; -extern struct platform_device vt8500_device_ehci; -extern struct platform_device vt8500_device_ge_rops; -extern struct platform_device vt8500_device_pwm; -extern struct platform_device vt8500_device_pwmbl; -extern struct platform_device vt8500_device_rtc; -#endif diff --git a/arch/arm/mach-vt8500/gpio.c b/arch/arm/mach-vt8500/gpio.c deleted file mode 100644 index 2bcc0ec783df..000000000000 --- a/arch/arm/mach-vt8500/gpio.c +++ /dev/null @@ -1,240 +0,0 @@ -/* linux/arch/arm/mach-vt8500/gpio.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> - -#include "devices.h" - -#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) - -#define ENABLE_REGS 0x0 -#define DIRECTION_REGS 0x20 -#define OUTVALUE_REGS 0x40 -#define INVALUE_REGS 0x60 - -#define EXT_REGOFF 0x1c - -static void __iomem *regbase; - -struct vt8500_gpio_chip { - struct gpio_chip chip; - unsigned int shift; - unsigned int regoff; -}; - -static int gpio_to_irq_map[8]; - -static int vt8500_muxed_gpio_request(struct gpio_chip *chip, - unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - unsigned val = readl(regbase + ENABLE_REGS + vt8500_chip->regoff); - - val |= (1 << vt8500_chip->shift << offset); - writel(val, regbase + ENABLE_REGS + vt8500_chip->regoff); - - return 0; -} - -static void vt8500_muxed_gpio_free(struct gpio_chip *chip, - unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - unsigned val = readl(regbase + ENABLE_REGS + vt8500_chip->regoff); - - val &= ~(1 << vt8500_chip->shift << offset); - writel(val, regbase + ENABLE_REGS + vt8500_chip->regoff); -} - -static int vt8500_muxed_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - unsigned val = readl(regbase + DIRECTION_REGS + vt8500_chip->regoff); - - val &= ~(1 << vt8500_chip->shift << offset); - writel(val, regbase + DIRECTION_REGS + vt8500_chip->regoff); - - return 0; -} - -static int vt8500_muxed_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - unsigned val = readl(regbase + DIRECTION_REGS + vt8500_chip->regoff); - - val |= (1 << vt8500_chip->shift << offset); - writel(val, regbase + DIRECTION_REGS + vt8500_chip->regoff); - - if (value) { - val = readl(regbase + OUTVALUE_REGS + vt8500_chip->regoff); - val |= (1 << vt8500_chip->shift << offset); - writel(val, regbase + OUTVALUE_REGS + vt8500_chip->regoff); - } - return 0; -} - -static int vt8500_muxed_gpio_get_value(struct gpio_chip *chip, - unsigned offset) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - - return (readl(regbase + INVALUE_REGS + vt8500_chip->regoff) - >> vt8500_chip->shift >> offset) & 1; -} - -static void vt8500_muxed_gpio_set_value(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); - unsigned val = readl(regbase + INVALUE_REGS + vt8500_chip->regoff); - - if (value) - val |= (1 << vt8500_chip->shift << offset); - else - val &= ~(1 << vt8500_chip->shift << offset); - - writel(val, regbase + INVALUE_REGS + vt8500_chip->regoff); -} - -#define VT8500_GPIO_BANK(__name, __shift, __off, __base, __num) \ -{ \ - .chip = { \ - .label = __name, \ - .request = vt8500_muxed_gpio_request, \ - .free = vt8500_muxed_gpio_free, \ - .direction_input = vt8500_muxed_gpio_direction_input, \ - .direction_output = vt8500_muxed_gpio_direction_output, \ - .get = vt8500_muxed_gpio_get_value, \ - .set = vt8500_muxed_gpio_set_value, \ - .can_sleep = 0, \ - .base = __base, \ - .ngpio = __num, \ - }, \ - .shift = __shift, \ - .regoff = __off, \ -} - -static struct vt8500_gpio_chip vt8500_muxed_gpios[] = { - VT8500_GPIO_BANK("uart0", 0, 0x0, 8, 4), - VT8500_GPIO_BANK("uart1", 4, 0x0, 12, 4), - VT8500_GPIO_BANK("spi0", 8, 0x0, 16, 4), - VT8500_GPIO_BANK("spi1", 12, 0x0, 20, 4), - VT8500_GPIO_BANK("spi2", 16, 0x0, 24, 4), - VT8500_GPIO_BANK("pwmout", 24, 0x0, 28, 2), - - VT8500_GPIO_BANK("sdmmc", 0, 0x4, 30, 11), - VT8500_GPIO_BANK("ms", 16, 0x4, 41, 7), - VT8500_GPIO_BANK("i2c0", 24, 0x4, 48, 2), - VT8500_GPIO_BANK("i2c1", 26, 0x4, 50, 2), - - VT8500_GPIO_BANK("mii", 0, 0x8, 52, 20), - VT8500_GPIO_BANK("see", 20, 0x8, 72, 4), - VT8500_GPIO_BANK("ide", 24, 0x8, 76, 7), - - VT8500_GPIO_BANK("ccir", 0, 0xc, 83, 19), - - VT8500_GPIO_BANK("ts", 8, 0x10, 102, 11), - - VT8500_GPIO_BANK("lcd", 0, 0x14, 113, 23), -}; - -static int vt8500_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - unsigned val = readl(regbase + DIRECTION_REGS + EXT_REGOFF); - - val &= ~(1 << offset); - writel(val, regbase + DIRECTION_REGS + EXT_REGOFF); - return 0; -} - -static int vt8500_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - unsigned val = readl(regbase + DIRECTION_REGS + EXT_REGOFF); - - val |= (1 << offset); - writel(val, regbase + DIRECTION_REGS + EXT_REGOFF); - - if (value) { - val = readl(regbase + OUTVALUE_REGS + EXT_REGOFF); - val |= (1 << offset); - writel(val, regbase + OUTVALUE_REGS + EXT_REGOFF); - } - return 0; -} - -static int vt8500_gpio_get_value(struct gpio_chip *chip, - unsigned offset) -{ - return (readl(regbase + INVALUE_REGS + EXT_REGOFF) >> offset) & 1; -} - -static void vt8500_gpio_set_value(struct gpio_chip *chip, - unsigned offset, int value) -{ - unsigned val = readl(regbase + OUTVALUE_REGS + EXT_REGOFF); - - if (value) - val |= (1 << offset); - else - val &= ~(1 << offset); - - writel(val, regbase + OUTVALUE_REGS + EXT_REGOFF); -} - -static int vt8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - if (offset > 7) - return -EINVAL; - - return gpio_to_irq_map[offset]; -} - -static struct gpio_chip vt8500_external_gpios = { - .label = "extgpio", - .direction_input = vt8500_gpio_direction_input, - .direction_output = vt8500_gpio_direction_output, - .get = vt8500_gpio_get_value, - .set = vt8500_gpio_set_value, - .to_irq = vt8500_gpio_to_irq, - .can_sleep = 0, - .base = 0, - .ngpio = 8, -}; - -void __init vt8500_gpio_init(void) -{ - int i; - - for (i = 0; i < 8; i++) - gpio_to_irq_map[i] = wmt_gpio_ext_irq[i]; - - regbase = ioremap(wmt_gpio_base, SZ_64K); - if (!regbase) { - printk(KERN_ERR "Failed to map MMIO registers for GPIO\n"); - return; - } - - gpiochip_add(&vt8500_external_gpios); - - for (i = 0; i < ARRAY_SIZE(vt8500_muxed_gpios); i++) - gpiochip_add(&vt8500_muxed_gpios[i].chip); -} diff --git a/arch/arm/mach-vt8500/include/mach/restart.h b/arch/arm/mach-vt8500/include/mach/restart.h index 89f9b787d2a0..738979518acb 100644 --- a/arch/arm/mach-vt8500/include/mach/restart.h +++ b/arch/arm/mach-vt8500/include/mach/restart.h @@ -13,5 +13,5 @@ * */ -void wmt_setup_restart(void); -void wmt_restart(char mode, const char *cmd); +void vt8500_setup_restart(void); +void vt8500_restart(char mode, const char *cmd); diff --git a/arch/arm/mach-vt8500/include/mach/vt8500_irqs.h b/arch/arm/mach-vt8500/include/mach/vt8500_irqs.h deleted file mode 100644 index ecfee9124711..000000000000 --- a/arch/arm/mach-vt8500/include/mach/vt8500_irqs.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * arch/arm/mach-vt8500/include/mach/vt8500_irqs.h - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* VT8500 Interrupt Sources */ - -#define IRQ_JPEGENC 0 /* JPEG Encoder */ -#define IRQ_JPEGDEC 1 /* JPEG Decoder */ - /* Reserved */ -#define IRQ_PATA 3 /* PATA Controller */ - /* Reserved */ -#define IRQ_DMA 5 /* DMA Controller */ -#define IRQ_EXT0 6 /* External Interrupt 0 */ -#define IRQ_EXT1 7 /* External Interrupt 1 */ -#define IRQ_GE 8 /* Graphic Engine */ -#define IRQ_GOV 9 /* Graphic Overlay Engine */ -#define IRQ_ETHER 10 /* Ethernet MAC */ -#define IRQ_MPEGTS 11 /* Transport Stream Interface */ -#define IRQ_LCDC 12 /* LCD Controller */ -#define IRQ_EXT2 13 /* External Interrupt 2 */ -#define IRQ_EXT3 14 /* External Interrupt 3 */ -#define IRQ_EXT4 15 /* External Interrupt 4 */ -#define IRQ_CIPHER 16 /* Cipher */ -#define IRQ_VPP 17 /* Video Post-Processor */ -#define IRQ_I2C1 18 /* I2C 1 */ -#define IRQ_I2C0 19 /* I2C 0 */ -#define IRQ_SDMMC 20 /* SD/MMC Controller */ -#define IRQ_SDMMC_DMA 21 /* SD/MMC Controller DMA */ -#define IRQ_PMC_WU 22 /* Power Management Controller Wakeup */ - /* Reserved */ -#define IRQ_SPI0 24 /* SPI 0 */ -#define IRQ_SPI1 25 /* SPI 1 */ -#define IRQ_SPI2 26 /* SPI 2 */ -#define IRQ_LCDDF 27 /* LCD Data Formatter */ -#define IRQ_NAND 28 /* NAND Flash Controller */ -#define IRQ_NAND_DMA 29 /* NAND Flash Controller DMA */ -#define IRQ_MS 30 /* MemoryStick Controller */ -#define IRQ_MS_DMA 31 /* MemoryStick Controller DMA */ -#define IRQ_UART0 32 /* UART 0 */ -#define IRQ_UART1 33 /* UART 1 */ -#define IRQ_I2S 34 /* I2S */ -#define IRQ_PCM 35 /* PCM */ -#define IRQ_PMCOS0 36 /* PMC OS Timer 0 */ -#define IRQ_PMCOS1 37 /* PMC OS Timer 1 */ -#define IRQ_PMCOS2 38 /* PMC OS Timer 2 */ -#define IRQ_PMCOS3 39 /* PMC OS Timer 3 */ -#define IRQ_VPU 40 /* Video Processing Unit */ -#define IRQ_VID 41 /* Video Digital Input Interface */ -#define IRQ_AC97 42 /* AC97 Interface */ -#define IRQ_EHCI 43 /* USB */ -#define IRQ_NOR 44 /* NOR Flash Controller */ -#define IRQ_PS2MOUSE 45 /* PS/2 Mouse */ -#define IRQ_PS2KBD 46 /* PS/2 Keyboard */ -#define IRQ_UART2 47 /* UART 2 */ -#define IRQ_RTC 48 /* RTC Interrupt */ -#define IRQ_RTCSM 49 /* RTC Second/Minute Update Interrupt */ -#define IRQ_UART3 50 /* UART 3 */ -#define IRQ_ADC 51 /* ADC */ -#define IRQ_EXT5 52 /* External Interrupt 5 */ -#define IRQ_EXT6 53 /* External Interrupt 6 */ -#define IRQ_EXT7 54 /* External Interrupt 7 */ -#define IRQ_CIR 55 /* CIR */ -#define IRQ_DMA0 56 /* DMA Channel 0 */ -#define IRQ_DMA1 57 /* DMA Channel 1 */ -#define IRQ_DMA2 58 /* DMA Channel 2 */ -#define IRQ_DMA3 59 /* DMA Channel 3 */ -#define IRQ_DMA4 60 /* DMA Channel 4 */ -#define IRQ_DMA5 61 /* DMA Channel 5 */ -#define IRQ_DMA6 62 /* DMA Channel 6 */ -#define IRQ_DMA7 63 /* DMA Channel 7 */ - -#define VT8500_NR_IRQS 64 diff --git a/arch/arm/mach-vt8500/include/mach/vt8500_regs.h b/arch/arm/mach-vt8500/include/mach/vt8500_regs.h deleted file mode 100644 index 29c63ecb2383..000000000000 --- a/arch/arm/mach-vt8500/include/mach/vt8500_regs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * arch/arm/mach-vt8500/include/mach/vt8500_regs.h - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARM_ARCH_VT8500_REGS_H -#define __ASM_ARM_ARCH_VT8500_REGS_H - -/* VT8500 Registers Map */ - -#define VT8500_REGS_START_PHYS 0xd8000000 /* Start of MMIO registers */ -#define VT8500_REGS_START_VIRT 0xf8000000 /* Virtual mapping start */ - -#define VT8500_DDR_BASE 0xd8000000 /* 1k DDR/DDR2 Memory - Controller */ -#define VT8500_DMA_BASE 0xd8001000 /* 1k DMA Controller */ -#define VT8500_SFLASH_BASE 0xd8002000 /* 1k Serial Flash Memory - Controller */ -#define VT8500_ETHER_BASE 0xd8004000 /* 1k Ethernet MAC 0 */ -#define VT8500_CIPHER_BASE 0xd8006000 /* 4k Cipher */ -#define VT8500_USB_BASE 0xd8007800 /* 2k USB OTG */ -# define VT8500_EHCI_BASE 0xd8007900 /* EHCI */ -# define VT8500_UHCI_BASE 0xd8007b01 /* UHCI */ -#define VT8500_PATA_BASE 0xd8008000 /* 512 PATA */ -#define VT8500_PS2_BASE 0xd8008800 /* 1k PS/2 */ -#define VT8500_NAND_BASE 0xd8009000 /* 1k NAND Controller */ -#define VT8500_NOR_BASE 0xd8009400 /* 1k NOR Controller */ -#define VT8500_SDMMC_BASE 0xd800a000 /* 1k SD/MMC Controller */ -#define VT8500_MS_BASE 0xd800b000 /* 1k MS/MSPRO Controller */ -#define VT8500_LCDC_BASE 0xd800e400 /* 1k LCD Controller */ -#define VT8500_VPU_BASE 0xd8050000 /* 256 VPU */ -#define VT8500_GOV_BASE 0xd8050300 /* 256 GOV */ -#define VT8500_GEGEA_BASE 0xd8050400 /* 768 GE/GE Alpha Mixing */ -#define VT8500_LCDF_BASE 0xd8050900 /* 256 LCD Formatter */ -#define VT8500_VID_BASE 0xd8050a00 /* 256 VID */ -#define VT8500_VPP_BASE 0xd8050b00 /* 256 VPP */ -#define VT8500_TSBK_BASE 0xd80f4000 /* 4k TSBK */ -#define VT8500_JPEGDEC_BASE 0xd80fe000 /* 4k JPEG Decoder */ -#define VT8500_JPEGENC_BASE 0xd80ff000 /* 4k JPEG Encoder */ -#define VT8500_RTC_BASE 0xd8100000 /* 64k RTC */ -#define VT8500_GPIO_BASE 0xd8110000 /* 64k GPIO Configuration */ -#define VT8500_SCC_BASE 0xd8120000 /* 64k System Configuration*/ -#define VT8500_PMC_BASE 0xd8130000 /* 64k PMC Configuration */ -#define VT8500_IC_BASE 0xd8140000 /* 64k Interrupt Controller*/ -#define VT8500_UART0_BASE 0xd8200000 /* 64k UART 0 */ -#define VT8500_UART2_BASE 0xd8210000 /* 64k UART 2 */ -#define VT8500_PWM_BASE 0xd8220000 /* 64k PWM Configuration */ -#define VT8500_SPI0_BASE 0xd8240000 /* 64k SPI 0 */ -#define VT8500_SPI1_BASE 0xd8250000 /* 64k SPI 1 */ -#define VT8500_CIR_BASE 0xd8270000 /* 64k CIR */ -#define VT8500_I2C0_BASE 0xd8280000 /* 64k I2C 0 */ -#define VT8500_AC97_BASE 0xd8290000 /* 64k AC97 */ -#define VT8500_SPI2_BASE 0xd82a0000 /* 64k SPI 2 */ -#define VT8500_UART1_BASE 0xd82b0000 /* 64k UART 1 */ -#define VT8500_UART3_BASE 0xd82c0000 /* 64k UART 3 */ -#define VT8500_PCM_BASE 0xd82d0000 /* 64k PCM */ -#define VT8500_I2C1_BASE 0xd8320000 /* 64k I2C 1 */ -#define VT8500_I2S_BASE 0xd8330000 /* 64k I2S */ -#define VT8500_ADC_BASE 0xd8340000 /* 64k ADC */ - -#define VT8500_REGS_END_PHYS 0xd834ffff /* End of MMIO registers */ -#define VT8500_REGS_LENGTH (VT8500_REGS_END_PHYS \ - - VT8500_REGS_START_PHYS + 1) - -#endif diff --git a/arch/arm/mach-vt8500/include/mach/wm8505_irqs.h b/arch/arm/mach-vt8500/include/mach/wm8505_irqs.h deleted file mode 100644 index 6128627ac753..000000000000 --- a/arch/arm/mach-vt8500/include/mach/wm8505_irqs.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * arch/arm/mach-vt8500/include/mach/wm8505_irqs.h - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* WM8505 Interrupt Sources */ - -#define IRQ_UHCI 0 /* UHC FS (UHCI?) */ -#define IRQ_EHCI 1 /* UHC HS */ -#define IRQ_UDCDMA 2 /* UDC DMA */ - /* Reserved */ -#define IRQ_PS2MOUSE 4 /* PS/2 Mouse */ -#define IRQ_UDC 5 /* UDC */ -#define IRQ_EXT0 6 /* External Interrupt 0 */ -#define IRQ_EXT1 7 /* External Interrupt 1 */ -#define IRQ_KEYPAD 8 /* Keypad */ -#define IRQ_DMA 9 /* DMA Controller */ -#define IRQ_ETHER 10 /* Ethernet MAC */ - /* Reserved */ - /* Reserved */ -#define IRQ_EXT2 13 /* External Interrupt 2 */ -#define IRQ_EXT3 14 /* External Interrupt 3 */ -#define IRQ_EXT4 15 /* External Interrupt 4 */ -#define IRQ_APB 16 /* APB Bridge */ -#define IRQ_DMA0 17 /* DMA Channel 0 */ -#define IRQ_I2C1 18 /* I2C 1 */ -#define IRQ_I2C0 19 /* I2C 0 */ -#define IRQ_SDMMC 20 /* SD/MMC Controller */ -#define IRQ_SDMMC_DMA 21 /* SD/MMC Controller DMA */ -#define IRQ_PMC_WU 22 /* Power Management Controller Wakeup */ -#define IRQ_PS2KBD 23 /* PS/2 Keyboard */ -#define IRQ_SPI0 24 /* SPI 0 */ -#define IRQ_SPI1 25 /* SPI 1 */ -#define IRQ_SPI2 26 /* SPI 2 */ -#define IRQ_DMA1 27 /* DMA Channel 1 */ -#define IRQ_NAND 28 /* NAND Flash Controller */ -#define IRQ_NAND_DMA 29 /* NAND Flash Controller DMA */ -#define IRQ_UART5 30 /* UART 5 */ -#define IRQ_UART4 31 /* UART 4 */ -#define IRQ_UART0 32 /* UART 0 */ -#define IRQ_UART1 33 /* UART 1 */ -#define IRQ_DMA2 34 /* DMA Channel 2 */ -#define IRQ_I2S 35 /* I2S */ -#define IRQ_PMCOS0 36 /* PMC OS Timer 0 */ -#define IRQ_PMCOS1 37 /* PMC OS Timer 1 */ -#define IRQ_PMCOS2 38 /* PMC OS Timer 2 */ -#define IRQ_PMCOS3 39 /* PMC OS Timer 3 */ -#define IRQ_DMA3 40 /* DMA Channel 3 */ -#define IRQ_DMA4 41 /* DMA Channel 4 */ -#define IRQ_AC97 42 /* AC97 Interface */ - /* Reserved */ -#define IRQ_NOR 44 /* NOR Flash Controller */ -#define IRQ_DMA5 45 /* DMA Channel 5 */ -#define IRQ_DMA6 46 /* DMA Channel 6 */ -#define IRQ_UART2 47 /* UART 2 */ -#define IRQ_RTC 48 /* RTC Interrupt */ -#define IRQ_RTCSM 49 /* RTC Second/Minute Update Interrupt */ -#define IRQ_UART3 50 /* UART 3 */ -#define IRQ_DMA7 51 /* DMA Channel 7 */ -#define IRQ_EXT5 52 /* External Interrupt 5 */ -#define IRQ_EXT6 53 /* External Interrupt 6 */ -#define IRQ_EXT7 54 /* External Interrupt 7 */ -#define IRQ_CIR 55 /* CIR */ -#define IRQ_SIC0 56 /* SIC IRQ0 */ -#define IRQ_SIC1 57 /* SIC IRQ1 */ -#define IRQ_SIC2 58 /* SIC IRQ2 */ -#define IRQ_SIC3 59 /* SIC IRQ3 */ -#define IRQ_SIC4 60 /* SIC IRQ4 */ -#define IRQ_SIC5 61 /* SIC IRQ5 */ -#define IRQ_SIC6 62 /* SIC IRQ6 */ -#define IRQ_SIC7 63 /* SIC IRQ7 */ - /* Reserved */ -#define IRQ_JPEGDEC 65 /* JPEG Decoder */ -#define IRQ_SAE 66 /* SAE (?) */ - /* Reserved */ -#define IRQ_VPU 79 /* Video Processing Unit */ -#define IRQ_VPP 80 /* Video Post-Processor */ -#define IRQ_VID 81 /* Video Digital Input Interface */ -#define IRQ_SPU 82 /* SPU (?) */ -#define IRQ_PIP 83 /* PIP Error */ -#define IRQ_GE 84 /* Graphic Engine */ -#define IRQ_GOV 85 /* Graphic Overlay Engine */ -#define IRQ_DVO 86 /* Digital Video Output */ - /* Reserved */ -#define IRQ_DMA8 92 /* DMA Channel 8 */ -#define IRQ_DMA9 93 /* DMA Channel 9 */ -#define IRQ_DMA10 94 /* DMA Channel 10 */ -#define IRQ_DMA11 95 /* DMA Channel 11 */ -#define IRQ_DMA12 96 /* DMA Channel 12 */ -#define IRQ_DMA13 97 /* DMA Channel 13 */ -#define IRQ_DMA14 98 /* DMA Channel 14 */ -#define IRQ_DMA15 99 /* DMA Channel 15 */ - /* Reserved */ -#define IRQ_GOVW 111 /* GOVW (?) */ -#define IRQ_GOVRSDSCD 112 /* GOVR SDSCD (?) */ -#define IRQ_GOVRSDMIF 113 /* GOVR SDMIF (?) */ -#define IRQ_GOVRHDSCD 114 /* GOVR HDSCD (?) */ -#define IRQ_GOVRHDMIF 115 /* GOVR HDMIF (?) */ - -#define WM8505_NR_IRQS 116 diff --git a/arch/arm/mach-vt8500/include/mach/wm8505_regs.h b/arch/arm/mach-vt8500/include/mach/wm8505_regs.h deleted file mode 100644 index df1550941efb..000000000000 --- a/arch/arm/mach-vt8500/include/mach/wm8505_regs.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * arch/arm/mach-vt8500/include/mach/wm8505_regs.h - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARM_ARCH_WM8505_REGS_H -#define __ASM_ARM_ARCH_WM8505_REGS_H - -/* WM8505 Registers Map */ - -#define WM8505_REGS_START_PHYS 0xd8000000 /* Start of MMIO registers */ -#define WM8505_REGS_START_VIRT 0xf8000000 /* Virtual mapping start */ - -#define WM8505_DDR_BASE 0xd8000400 /* 1k DDR/DDR2 Memory - Controller */ -#define WM8505_DMA_BASE 0xd8001800 /* 1k DMA Controller */ -#define WM8505_VDMA_BASE 0xd8001c00 /* 1k VDMA */ -#define WM8505_SFLASH_BASE 0xd8002000 /* 1k Serial Flash Memory - Controller */ -#define WM8505_ETHER_BASE 0xd8004000 /* 1k Ethernet MAC 0 */ -#define WM8505_CIPHER_BASE 0xd8006000 /* 4k Cipher */ -#define WM8505_USB_BASE 0xd8007000 /* 2k USB 2.0 Host */ -# define WM8505_EHCI_BASE 0xd8007100 /* EHCI */ -# define WM8505_UHCI_BASE 0xd8007301 /* UHCI */ -#define WM8505_PS2_BASE 0xd8008800 /* 1k PS/2 */ -#define WM8505_NAND_BASE 0xd8009000 /* 1k NAND Controller */ -#define WM8505_NOR_BASE 0xd8009400 /* 1k NOR Controller */ -#define WM8505_SDMMC_BASE 0xd800a000 /* 1k SD/MMC Controller */ -#define WM8505_VPU_BASE 0xd8050000 /* 256 VPU */ -#define WM8505_GOV_BASE 0xd8050300 /* 256 GOV */ -#define WM8505_GEGEA_BASE 0xd8050400 /* 768 GE/GE Alpha Mixing */ -#define WM8505_GOVR_BASE 0xd8050800 /* 512 GOVR (frambuffer) */ -#define WM8505_VID_BASE 0xd8050a00 /* 256 VID */ -#define WM8505_SCL_BASE 0xd8050d00 /* 256 SCL */ -#define WM8505_VPP_BASE 0xd8050f00 /* 256 VPP */ -#define WM8505_JPEGDEC_BASE 0xd80fe000 /* 4k JPEG Decoder */ -#define WM8505_RTC_BASE 0xd8100000 /* 64k RTC */ -#define WM8505_GPIO_BASE 0xd8110000 /* 64k GPIO Configuration */ -#define WM8505_SCC_BASE 0xd8120000 /* 64k System Configuration*/ -#define WM8505_PMC_BASE 0xd8130000 /* 64k PMC Configuration */ -#define WM8505_IC_BASE 0xd8140000 /* 64k Interrupt Controller*/ -#define WM8505_SIC_BASE 0xd8150000 /* 64k Secondary IC */ -#define WM8505_UART0_BASE 0xd8200000 /* 64k UART 0 */ -#define WM8505_UART2_BASE 0xd8210000 /* 64k UART 2 */ -#define WM8505_PWM_BASE 0xd8220000 /* 64k PWM Configuration */ -#define WM8505_SPI0_BASE 0xd8240000 /* 64k SPI 0 */ -#define WM8505_SPI1_BASE 0xd8250000 /* 64k SPI 1 */ -#define WM8505_KEYPAD_BASE 0xd8260000 /* 64k Keypad control */ -#define WM8505_CIR_BASE 0xd8270000 /* 64k CIR */ -#define WM8505_I2C0_BASE 0xd8280000 /* 64k I2C 0 */ -#define WM8505_AC97_BASE 0xd8290000 /* 64k AC97 */ -#define WM8505_SPI2_BASE 0xd82a0000 /* 64k SPI 2 */ -#define WM8505_UART1_BASE 0xd82b0000 /* 64k UART 1 */ -#define WM8505_UART3_BASE 0xd82c0000 /* 64k UART 3 */ -#define WM8505_I2C1_BASE 0xd8320000 /* 64k I2C 1 */ -#define WM8505_I2S_BASE 0xd8330000 /* 64k I2S */ -#define WM8505_UART4_BASE 0xd8370000 /* 64k UART 4 */ -#define WM8505_UART5_BASE 0xd8380000 /* 64k UART 5 */ - -#define WM8505_REGS_END_PHYS 0xd838ffff /* End of MMIO registers */ -#define WM8505_REGS_LENGTH (WM8505_REGS_END_PHYS \ - - WM8505_REGS_START_PHYS + 1) - -#endif diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c index 642de0408f25..f8f9ab9bc56e 100644 --- a/arch/arm/mach-vt8500/irq.c +++ b/arch/arm/mach-vt8500/irq.c @@ -1,6 +1,7 @@ /* * arch/arm/mach-vt8500/irq.c * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -18,81 +19,102 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * This file is copied and modified from the original irq.c provided by + * Alexey Charkov. Minor changes have been made for Device Tree Support. + */ + +#include <linux/slab.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/interrupt.h> +#include <linux/bitops.h> + +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> #include <asm/irq.h> -#include "devices.h" -#define VT8500_IC_DCTR 0x40 /* Destination control - register, 64*u8 */ -#define VT8500_INT_ENABLE (1 << 3) -#define VT8500_TRIGGER_HIGH (0 << 4) -#define VT8500_TRIGGER_RISING (1 << 4) -#define VT8500_TRIGGER_FALLING (2 << 4) +#define VT8500_ICPC_IRQ 0x20 +#define VT8500_ICPC_FIQ 0x24 +#define VT8500_ICDC 0x40 /* Destination Control 64*u32 */ +#define VT8500_ICIS 0x80 /* Interrupt status, 16*u32 */ + +/* ICPC */ +#define ICPC_MASK 0x3F +#define ICPC_ROTATE BIT(6) + +/* IC_DCTR */ +#define ICDC_IRQ 0x00 +#define ICDC_FIQ 0x01 +#define ICDC_DSS0 0x02 +#define ICDC_DSS1 0x03 +#define ICDC_DSS2 0x04 +#define ICDC_DSS3 0x05 +#define ICDC_DSS4 0x06 +#define ICDC_DSS5 0x07 + +#define VT8500_INT_DISABLE 0 +#define VT8500_INT_ENABLE BIT(3) + +#define VT8500_TRIGGER_HIGH 0 +#define VT8500_TRIGGER_RISING BIT(5) +#define VT8500_TRIGGER_FALLING BIT(6) #define VT8500_EDGE ( VT8500_TRIGGER_RISING \ | VT8500_TRIGGER_FALLING) -#define VT8500_IC_STATUS 0x80 /* Interrupt status, 2*u32 */ -static void __iomem *ic_regbase; -static void __iomem *sic_regbase; +static int irq_cnt; + +struct vt8500_irq_priv { + void __iomem *base; +}; static void vt8500_irq_mask(struct irq_data *d) { - void __iomem *base = ic_regbase; - unsigned irq = d->irq; + struct vt8500_irq_priv *priv = + (struct vt8500_irq_priv *)(d->domain->host_data); + void __iomem *base = priv->base; u8 edge; - if (irq >= 64) { - base = sic_regbase; - irq -= 64; - } - edge = readb(base + VT8500_IC_DCTR + irq) & VT8500_EDGE; + edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE; if (edge) { - void __iomem *stat_reg = base + VT8500_IC_STATUS - + (irq < 32 ? 0 : 4); + void __iomem *stat_reg = base + VT8500_ICIS + + (d->hwirq < 32 ? 0 : 4); unsigned status = readl(stat_reg); - status |= (1 << (irq & 0x1f)); + status |= (1 << (d->hwirq & 0x1f)); writel(status, stat_reg); } else { - u8 dctr = readb(base + VT8500_IC_DCTR + irq); + u8 dctr = readb(base + VT8500_ICDC + d->hwirq); dctr &= ~VT8500_INT_ENABLE; - writeb(dctr, base + VT8500_IC_DCTR + irq); + writeb(dctr, base + VT8500_ICDC + d->hwirq); } } static void vt8500_irq_unmask(struct irq_data *d) { - void __iomem *base = ic_regbase; - unsigned irq = d->irq; + struct vt8500_irq_priv *priv = + (struct vt8500_irq_priv *)(d->domain->host_data); + void __iomem *base = priv->base; u8 dctr; - if (irq >= 64) { - base = sic_regbase; - irq -= 64; - } - dctr = readb(base + VT8500_IC_DCTR + irq); + dctr = readb(base + VT8500_ICDC + d->hwirq); dctr |= VT8500_INT_ENABLE; - writeb(dctr, base + VT8500_IC_DCTR + irq); + writeb(dctr, base + VT8500_ICDC + d->hwirq); } static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) { - void __iomem *base = ic_regbase; - unsigned irq = d->irq; - unsigned orig_irq = irq; + struct vt8500_irq_priv *priv = + (struct vt8500_irq_priv *)(d->domain->host_data); + void __iomem *base = priv->base; u8 dctr; - if (irq >= 64) { - base = sic_regbase; - irq -= 64; - } - - dctr = readb(base + VT8500_IC_DCTR + irq); + dctr = readb(base + VT8500_ICDC + d->hwirq); dctr &= ~VT8500_EDGE; switch (flow_type) { @@ -100,18 +122,18 @@ static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) return -EINVAL; case IRQF_TRIGGER_HIGH: dctr |= VT8500_TRIGGER_HIGH; - __irq_set_handler_locked(orig_irq, handle_level_irq); + __irq_set_handler_locked(d->irq, handle_level_irq); break; case IRQF_TRIGGER_FALLING: dctr |= VT8500_TRIGGER_FALLING; - __irq_set_handler_locked(orig_irq, handle_edge_irq); + __irq_set_handler_locked(d->irq, handle_edge_irq); break; case IRQF_TRIGGER_RISING: dctr |= VT8500_TRIGGER_RISING; - __irq_set_handler_locked(orig_irq, handle_edge_irq); + __irq_set_handler_locked(d->irq, handle_edge_irq); break; } - writeb(dctr, base + VT8500_IC_DCTR + irq); + writeb(dctr, base + VT8500_ICDC + d->hwirq); return 0; } @@ -124,57 +146,76 @@ static struct irq_chip vt8500_irq_chip = { .irq_set_type = vt8500_irq_set_type, }; -void __init vt8500_init_irq(void) +static void __init vt8500_init_irq_hw(void __iomem *base) { unsigned int i; - ic_regbase = ioremap(wmt_ic_base, SZ_64K); + /* Enable rotating priority for IRQ */ + writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ); + writel(0x00, base + VT8500_ICPC_FIQ); - if (ic_regbase) { - /* Enable rotating priority for IRQ */ - writel((1 << 6), ic_regbase + 0x20); - writel(0, ic_regbase + 0x24); + for (i = 0; i < 64; i++) { + /* Disable all interrupts and route them to IRQ */ + writeb(VT8500_INT_DISABLE | ICDC_IRQ, + base + VT8500_ICDC + i); + } +} - for (i = 0; i < wmt_nr_irqs; i++) { - /* Disable all interrupts and route them to IRQ */ - writeb(0x00, ic_regbase + VT8500_IC_DCTR + i); +static int vt8500_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &vt8500_irq_chip, handle_level_irq); + set_irq_flags(virq, IRQF_VALID); - irq_set_chip_and_handler(i, &vt8500_irq_chip, - handle_level_irq); - set_irq_flags(i, IRQF_VALID); - } - } else { - printk(KERN_ERR "Unable to remap the Interrupt Controller registers, not enabling IRQs!\n"); - } + return 0; } -void __init wm8505_init_irq(void) +static struct irq_domain_ops vt8500_irq_domain_ops = { + .map = vt8500_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +int __init vt8500_irq_init(struct device_node *node, struct device_node *parent) { - unsigned int i; + struct irq_domain *vt8500_irq_domain; + struct vt8500_irq_priv *priv; + int irq, i; + struct device_node *np = node; + + priv = kzalloc(sizeof(struct vt8500_irq_priv), GFP_KERNEL); + priv->base = of_iomap(np, 0); + + vt8500_irq_domain = irq_domain_add_legacy(node, 64, irq_cnt, 0, + &vt8500_irq_domain_ops, priv); + if (!vt8500_irq_domain) + pr_err("%s: Unable to add wmt irq domain!\n", __func__); + + irq_set_default_host(vt8500_irq_domain); + + vt8500_init_irq_hw(priv->base); - ic_regbase = ioremap(wmt_ic_base, SZ_64K); - sic_regbase = ioremap(wmt_sic_base, SZ_64K); - - if (ic_regbase && sic_regbase) { - /* Enable rotating priority for IRQ */ - writel((1 << 6), ic_regbase + 0x20); - writel(0, ic_regbase + 0x24); - writel((1 << 6), sic_regbase + 0x20); - writel(0, sic_regbase + 0x24); - - for (i = 0; i < wmt_nr_irqs; i++) { - /* Disable all interrupts and route them to IRQ */ - if (i < 64) - writeb(0x00, ic_regbase + VT8500_IC_DCTR + i); - else - writeb(0x00, sic_regbase + VT8500_IC_DCTR - + i - 64); - - irq_set_chip_and_handler(i, &vt8500_irq_chip, - handle_level_irq); - set_irq_flags(i, IRQF_VALID); + pr_info("Added IRQ Controller @ %x [virq_base = %d]\n", + (u32)(priv->base), irq_cnt); + + /* check if this is a slaved controller */ + if (of_irq_count(np) != 0) { + /* check that we have the correct number of interrupts */ + if (of_irq_count(np) != 8) { + pr_err("%s: Incorrect IRQ map for slave controller\n", + __func__); + return -EINVAL; } - } else { - printk(KERN_ERR "Unable to remap the Interrupt Controller registers, not enabling IRQs!\n"); + + for (i = 0; i < 8; i++) { + irq = irq_of_parse_and_map(np, i); + enable_irq(irq); + } + + pr_info("vt8500-irq: Enabled slave->parent interrupts\n"); } + + irq_cnt += 64; + + return 0; } + diff --git a/arch/arm/mach-vt8500/restart.c b/arch/arm/mach-vt8500/restart.c deleted file mode 100644 index 497e89a5e130..000000000000 --- a/arch/arm/mach-vt8500/restart.c +++ /dev/null @@ -1,54 +0,0 @@ -/* linux/arch/arm/mach-vt8500/restart.c - * - * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <asm/io.h> -#include <linux/of.h> -#include <linux/of_address.h> - -#define LEGACY_PMC_BASE 0xD8130000 -#define WMT_PRIZM_PMSR_REG 0x60 - -static void __iomem *pmc_base; - -void wmt_setup_restart(void) -{ - struct device_node *np; - - /* - * Check if Power Mgmt Controller node is present in device tree. If no - * device tree node, use the legacy PMSR value (valid for all current - * SoCs). - */ - np = of_find_compatible_node(NULL, NULL, "wmt,prizm-pmc"); - if (np) { - pmc_base = of_iomap(np, 0); - - if (!pmc_base) - pr_err("%s:of_iomap(pmc) failed\n", __func__); - - of_node_put(np); - } else { - pmc_base = ioremap(LEGACY_PMC_BASE, 0x1000); - if (!pmc_base) { - pr_err("%s:ioremap(rstc) failed\n", __func__); - return; - } - } -} - -void wmt_restart(char mode, const char *cmd) -{ - if (pmc_base) - writel(1, pmc_base + WMT_PRIZM_PMSR_REG); -} diff --git a/arch/arm/mach-vt8500/timer.c b/arch/arm/mach-vt8500/timer.c index d5376c592ab6..050e1833f2d0 100644 --- a/arch/arm/mach-vt8500/timer.c +++ b/arch/arm/mach-vt8500/timer.c @@ -1,6 +1,7 @@ /* - * arch/arm/mach-vt8500/timer.c + * arch/arm/mach-vt8500/timer_dt.c * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -18,18 +19,25 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * This file is copied and modified from the original timer.c provided by + * Alexey Charkov. Minor changes have been made for Device Tree Support. + */ + #include <linux/io.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/clocksource.h> #include <linux/clockchips.h> #include <linux/delay.h> - #include <asm/mach/time.h> -#include "devices.h" +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #define VT8500_TIMER_OFFSET 0x0100 +#define VT8500_TIMER_HZ 3000000 #define TIMER_MATCH_VAL 0x0000 #define TIMER_COUNT_VAL 0x0010 #define TIMER_STATUS_VAL 0x0014 @@ -39,7 +47,6 @@ #define TIMER_COUNT_R_ACTIVE (1 << 5) /* not ready for read */ #define TIMER_COUNT_W_ACTIVE (1 << 4) /* not ready for write */ #define TIMER_MATCH_W_ACTIVE (1 << 0) /* not ready for write */ -#define VT8500_TIMER_HZ 3000000 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) @@ -55,7 +62,7 @@ static cycle_t vt8500_timer_read(struct clocksource *cs) return readl(regbase + TIMER_COUNT_VAL); } -struct clocksource clocksource = { +static struct clocksource clocksource = { .name = "vt8500_timer", .rating = 200, .read = vt8500_timer_read, @@ -98,7 +105,7 @@ static void vt8500_timer_set_mode(enum clock_event_mode mode, } } -struct clock_event_device clockevent = { +static struct clock_event_device clockevent = { .name = "vt8500_timer", .features = CLOCK_EVT_FEAT_ONESHOT, .rating = 200, @@ -115,26 +122,51 @@ static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -struct irqaction irq = { +static struct irqaction irq = { .name = "vt8500_timer", .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = vt8500_timer_interrupt, .dev_id = &clockevent, }; -static void __init vt8500_timer_init(void) +static struct of_device_id vt8500_timer_ids[] = { + { .compatible = "via,vt8500-timer" }, + { } +}; + +void __init vt8500_timer_init(void) { - regbase = ioremap(wmt_pmc_base + VT8500_TIMER_OFFSET, 0x28); - if (!regbase) - printk(KERN_ERR "vt8500_timer_init: failed to map MMIO registers\n"); + struct device_node *np; + int timer_irq; + + np = of_find_matching_node(NULL, vt8500_timer_ids); + if (!np) { + pr_err("%s: Timer description missing from Device Tree\n", + __func__); + return; + } + regbase = of_iomap(np, 0); + if (!regbase) { + pr_err("%s: Missing iobase description in Device Tree\n", + __func__); + of_node_put(np); + return; + } + timer_irq = irq_of_parse_and_map(np, 0); + if (!timer_irq) { + pr_err("%s: Missing irq description in Device Tree\n", + __func__); + of_node_put(np); + return; + } writel(1, regbase + TIMER_CTRL_VAL); writel(0xf, regbase + TIMER_STATUS_VAL); writel(~0, regbase + TIMER_MATCH_VAL); if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ)) - printk(KERN_ERR "vt8500_timer_init: clocksource_register failed for %s\n", - clocksource.name); + pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n", + __func__, clocksource.name); clockevents_calc_mult_shift(&clockevent, VT8500_TIMER_HZ, 4); @@ -144,12 +176,9 @@ static void __init vt8500_timer_init(void) clockevent.min_delta_ns = clockevent_delta2ns(4, &clockevent); clockevent.cpumask = cpumask_of(0); - if (setup_irq(wmt_timer_irq, &irq)) - printk(KERN_ERR "vt8500_timer_init: setup_irq failed for %s\n", - clockevent.name); + if (setup_irq(timer_irq, &irq)) + pr_err("%s: setup_irq failed for %s\n", __func__, + clockevent.name); clockevents_register_device(&clockevent); } -struct sys_timer vt8500_timer = { - .init = vt8500_timer_init -}; diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c new file mode 100644 index 000000000000..449499354449 --- /dev/null +++ b/arch/arm/mach-vt8500/vt8500.c @@ -0,0 +1,196 @@ +/* + * arch/arm/mach-vt8500/vt8500.c + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/io.h> +#include <linux/pm.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> + +#include <mach/restart.h> +#include <mach/gpio.h> + +#include "common.h" + +#define LEGACY_GPIO_BASE 0xD8110000 +#define LEGACY_PMC_BASE 0xD8130000 + +/* Registers in GPIO Controller */ +#define VT8500_GPIO_MUX_REG 0x200 + +/* Registers in Power Management Controller */ +#define VT8500_HCR_REG 0x12 +#define VT8500_PMSR_REG 0x60 + +static void __iomem *pmc_base; + +void vt8500_restart(char mode, const char *cmd) +{ + if (pmc_base) + writel(1, pmc_base + VT8500_PMSR_REG); +} + +static struct map_desc vt8500_io_desc[] __initdata = { + /* SoC MMIO registers */ + [0] = { + .virtual = 0xf8000000, + .pfn = __phys_to_pfn(0xd8000000), + .length = 0x00390000, /* max of all chip variants */ + .type = MT_DEVICE + }, +}; + +void __init vt8500_map_io(void) +{ + iotable_init(vt8500_io_desc, ARRAY_SIZE(vt8500_io_desc)); +} + +static void vt8500_power_off(void) +{ + local_irq_disable(); + writew(5, pmc_base + VT8500_HCR_REG); + asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0)); +} + +void __init vt8500_init(void) +{ + struct device_node *np, *fb; + void __iomem *gpio_base; + +#ifdef CONFIG_FB_VT8500 + fb = of_find_compatible_node(NULL, NULL, "via,vt8500-fb"); + if (fb) { + np = of_find_compatible_node(NULL, NULL, "via,vt8500-gpio"); + if (np) { + gpio_base = of_iomap(np, 0); + + if (!gpio_base) + pr_err("%s: of_iomap(gpio_mux) failed\n", + __func__); + + of_node_put(np); + } else { + gpio_base = ioremap(LEGACY_GPIO_BASE, 0x1000); + if (!gpio_base) + pr_err("%s: ioremap(legacy_gpio_mux) failed\n", + __func__); + } + if (gpio_base) { + writel(readl(gpio_base + VT8500_GPIO_MUX_REG) | 1, + gpio_base + VT8500_GPIO_MUX_REG); + iounmap(gpio_base); + } else + pr_err("%s: Could not remap GPIO mux\n", __func__); + + of_node_put(fb); + } +#endif + +#ifdef CONFIG_FB_WM8505 + fb = of_find_compatible_node(NULL, NULL, "wm,wm8505-fb"); + if (fb) { + np = of_find_compatible_node(NULL, NULL, "wm,wm8505-gpio"); + if (!np) + np = of_find_compatible_node(NULL, NULL, + "wm,wm8650-gpio"); + if (np) { + gpio_base = of_iomap(np, 0); + + if (!gpio_base) + pr_err("%s: of_iomap(gpio_mux) failed\n", + __func__); + + of_node_put(np); + } else { + gpio_base = ioremap(LEGACY_GPIO_BASE, 0x1000); + if (!gpio_base) + pr_err("%s: ioremap(legacy_gpio_mux) failed\n", + __func__); + } + if (gpio_base) { + writel(readl(gpio_base + VT8500_GPIO_MUX_REG) | + 0x80000000, gpio_base + VT8500_GPIO_MUX_REG); + iounmap(gpio_base); + } else + pr_err("%s: Could not remap GPIO mux\n", __func__); + + of_node_put(fb); + } +#endif + + np = of_find_compatible_node(NULL, NULL, "via,vt8500-pmc"); + if (np) { + pmc_base = of_iomap(np, 0); + + if (!pmc_base) + pr_err("%s:of_iomap(pmc) failed\n", __func__); + + of_node_put(np); + } else { + pmc_base = ioremap(LEGACY_PMC_BASE, 0x1000); + if (!pmc_base) + pr_err("%s:ioremap(power_off) failed\n", __func__); + } + if (pmc_base) + pm_power_off = &vt8500_power_off; + else + pr_err("%s: PMC Hibernation register could not be remapped, not enabling power off!\n", __func__); + + vtwm_clk_init(pmc_base); + + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static const struct of_device_id vt8500_irq_match[] __initconst = { + { .compatible = "via,vt8500-intc", .data = vt8500_irq_init, }, + { /* sentinel */ }, +}; + +static void __init vt8500_init_irq(void) +{ + of_irq_init(vt8500_irq_match); +}; + +static struct sys_timer vt8500_timer = { + .init = vt8500_timer_init, +}; + +static const char * const vt8500_dt_compat[] = { + "via,vt8500", + "wm,wm8650", + "wm,wm8505", +}; + +DT_MACHINE_START(WMT_DT, "VIA/Wondermedia SoC (Device Tree Support)") + .dt_compat = vt8500_dt_compat, + .map_io = vt8500_map_io, + .init_irq = vt8500_init_irq, + .timer = &vt8500_timer, + .init_machine = vt8500_init, + .restart = vt8500_restart, +MACHINE_END + diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c deleted file mode 100644 index db19886caf7c..000000000000 --- a/arch/arm/mach-vt8500/wm8505_7in.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * arch/arm/mach-vt8500/wm8505_7in.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/io.h> -#include <linux/pm.h> - -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <mach/restart.h> - -#include "devices.h" - -static void __iomem *pmc_hiber; - -static struct platform_device *devices[] __initdata = { - &vt8500_device_uart0, - &vt8500_device_ehci, - &vt8500_device_wm8505_fb, - &vt8500_device_ge_rops, - &vt8500_device_pwm, - &vt8500_device_pwmbl, - &vt8500_device_rtc, -}; - -static void vt8500_power_off(void) -{ - local_irq_disable(); - writew(5, pmc_hiber); - asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0)); -} - -void __init wm8505_7in_init(void) -{ -#ifdef CONFIG_FB_WM8505 - void __iomem *gpio_mux_reg = ioremap(wmt_gpio_base + 0x200, 4); - if (gpio_mux_reg) { - writel(readl(gpio_mux_reg) | 0x80000000, gpio_mux_reg); - iounmap(gpio_mux_reg); - } else { - printk(KERN_ERR "Could not remap the GPIO mux register, display may not work properly!\n"); - } -#endif - pmc_hiber = ioremap(wmt_pmc_base + 0x12, 2); - if (pmc_hiber) - pm_power_off = &vt8500_power_off; - else - printk(KERN_ERR "PMC Hibernation register could not be remapped, not enabling power off!\n"); - wmt_setup_restart(); - wm8505_set_resources(); - platform_add_devices(devices, ARRAY_SIZE(devices)); - vt8500_gpio_init(); -} - -MACHINE_START(WM8505_7IN_NETBOOK, "WM8505 7-inch generic netbook") - .atag_offset = 0x100, - .restart = wmt_restart, - .reserve = wm8505_reserve_mem, - .map_io = wm8505_map_io, - .init_irq = wm8505_init_irq, - .timer = &vt8500_timer, - .init_machine = wm8505_7in_init, -MACHINE_END diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 6327536b4900..e48e0da5a884 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ endif obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o obj-$(CONFIG_ARCH_U8500) += ux500/ +obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c new file mode 100644 index 000000000000..a885600f5270 --- /dev/null +++ b/drivers/clk/clk-vt8500.c @@ -0,0 +1,510 @@ +/* + * Clock implementation for VIA/Wondermedia SoC's + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/bitops.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> + +/* All clocks share the same lock as none can be changed concurrently */ +static DEFINE_SPINLOCK(_lock); + +struct clk_device { + struct clk_hw hw; + void __iomem *div_reg; + unsigned int div_mask; + void __iomem *en_reg; + int en_bit; + spinlock_t *lock; +}; + +/* + * Add new PLL_TYPE_x definitions here as required. Use the first known model + * to support the new type as the name. + * Add case statements to vtwm_pll_recalc_rate(), vtwm_pll_round_round() and + * vtwm_pll_set_rate() to handle the new PLL_TYPE_x + */ + +#define PLL_TYPE_VT8500 0 +#define PLL_TYPE_WM8650 1 + +struct clk_pll { + struct clk_hw hw; + void __iomem *reg; + spinlock_t *lock; + int type; +}; + +static void __iomem *pmc_base; + +#define to_clk_device(_hw) container_of(_hw, struct clk_device, hw) + +#define VT8500_PMC_BUSY_MASK 0x18 + +static void vt8500_pmc_wait_busy(void) +{ + while (readl(pmc_base) & VT8500_PMC_BUSY_MASK) + cpu_relax(); +} + +static int vt8500_dclk_enable(struct clk_hw *hw) +{ + struct clk_device *cdev = to_clk_device(hw); + u32 en_val; + unsigned long flags = 0; + + spin_lock_irqsave(cdev->lock, flags); + + en_val = readl(cdev->en_reg); + en_val |= BIT(cdev->en_bit); + writel(en_val, cdev->en_reg); + + spin_unlock_irqrestore(cdev->lock, flags); + return 0; +} + +static void vt8500_dclk_disable(struct clk_hw *hw) +{ + struct clk_device *cdev = to_clk_device(hw); + u32 en_val; + unsigned long flags = 0; + + spin_lock_irqsave(cdev->lock, flags); + + en_val = readl(cdev->en_reg); + en_val &= ~BIT(cdev->en_bit); + writel(en_val, cdev->en_reg); + + spin_unlock_irqrestore(cdev->lock, flags); +} + +static int vt8500_dclk_is_enabled(struct clk_hw *hw) +{ + struct clk_device *cdev = to_clk_device(hw); + u32 en_val = (readl(cdev->en_reg) & BIT(cdev->en_bit)); + + return en_val ? 1 : 0; +} + +static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_device *cdev = to_clk_device(hw); + u32 div = readl(cdev->div_reg) & cdev->div_mask; + + /* Special case for SDMMC devices */ + if ((cdev->div_mask == 0x3F) && (div & BIT(5))) + div = 64 * (div & 0x1f); + + /* div == 0 is actually the highest divisor */ + if (div == 0) + div = (cdev->div_mask + 1); + + return parent_rate / div; +} + +static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u32 divisor = *prate / rate; + + return *prate / divisor; +} + +static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_device *cdev = to_clk_device(hw); + u32 divisor = parent_rate / rate; + unsigned long flags = 0; + + if (divisor == cdev->div_mask + 1) + divisor = 0; + + if (divisor > cdev->div_mask) { + pr_err("%s: invalid divisor for clock\n", __func__); + return -EINVAL; + } + + spin_lock_irqsave(cdev->lock, flags); + + vt8500_pmc_wait_busy(); + writel(divisor, cdev->div_reg); + vt8500_pmc_wait_busy(); + + spin_lock_irqsave(cdev->lock, flags); + + return 0; +} + + +static const struct clk_ops vt8500_gated_clk_ops = { + .enable = vt8500_dclk_enable, + .disable = vt8500_dclk_disable, + .is_enabled = vt8500_dclk_is_enabled, +}; + +static const struct clk_ops vt8500_divisor_clk_ops = { + .round_rate = vt8500_dclk_round_rate, + .set_rate = vt8500_dclk_set_rate, + .recalc_rate = vt8500_dclk_recalc_rate, +}; + +static const struct clk_ops vt8500_gated_divisor_clk_ops = { + .enable = vt8500_dclk_enable, + .disable = vt8500_dclk_disable, + .is_enabled = vt8500_dclk_is_enabled, + .round_rate = vt8500_dclk_round_rate, + .set_rate = vt8500_dclk_set_rate, + .recalc_rate = vt8500_dclk_recalc_rate, +}; + +#define CLK_INIT_GATED BIT(0) +#define CLK_INIT_DIVISOR BIT(1) +#define CLK_INIT_GATED_DIVISOR (CLK_INIT_DIVISOR | CLK_INIT_GATED) + +static __init void vtwm_device_clk_init(struct device_node *node) +{ + u32 en_reg, div_reg; + struct clk *clk; + struct clk_device *dev_clk; + const char *clk_name = node->name; + const char *parent_name; + struct clk_init_data init; + int rc; + int clk_init_flags = 0; + + dev_clk = kzalloc(sizeof(*dev_clk), GFP_KERNEL); + if (WARN_ON(!dev_clk)) + return; + + dev_clk->lock = &_lock; + + rc = of_property_read_u32(node, "enable-reg", &en_reg); + if (!rc) { + dev_clk->en_reg = pmc_base + en_reg; + rc = of_property_read_u32(node, "enable-bit", &dev_clk->en_bit); + if (rc) { + pr_err("%s: enable-bit property required for gated clock\n", + __func__); + return; + } + clk_init_flags |= CLK_INIT_GATED; + } + + rc = of_property_read_u32(node, "divisor-reg", &div_reg); + if (!rc) { + dev_clk->div_reg = pmc_base + div_reg; + /* + * use 0x1f as the default mask since it covers + * almost all the clocks and reduces dts properties + */ + dev_clk->div_mask = 0x1f; + + of_property_read_u32(node, "divisor-mask", &dev_clk->div_mask); + clk_init_flags |= CLK_INIT_DIVISOR; + } + + of_property_read_string(node, "clock-output-names", &clk_name); + + switch (clk_init_flags) { + case CLK_INIT_GATED: + init.ops = &vt8500_gated_clk_ops; + break; + case CLK_INIT_DIVISOR: + init.ops = &vt8500_divisor_clk_ops; + break; + case CLK_INIT_GATED_DIVISOR: + init.ops = &vt8500_gated_divisor_clk_ops; + break; + default: + pr_err("%s: Invalid clock description in device tree\n", + __func__); + kfree(dev_clk); + return; + } + + init.name = clk_name; + init.flags = 0; + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + + dev_clk->hw.init = &init; + + clk = clk_register(NULL, &dev_clk->hw); + if (WARN_ON(IS_ERR(clk))) { + kfree(dev_clk); + return; + } + rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); +} + + +/* PLL clock related functions */ + +#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) + +/* Helper macros for PLL_VT8500 */ +#define VT8500_PLL_MUL(x) ((x & 0x1F) << 1) +#define VT8500_PLL_DIV(x) ((x & 0x100) ? 1 : 2) + +#define VT8500_BITS_TO_FREQ(r, m, d) \ + ((r / d) * m) + +#define VT8500_BITS_TO_VAL(m, d) \ + ((d == 2 ? 0 : 0x100) | ((m >> 1) & 0x1F)) + +/* Helper macros for PLL_WM8650 */ +#define WM8650_PLL_MUL(x) (x & 0x3FF) +#define WM8650_PLL_DIV(x) (((x >> 10) & 7) * (1 << ((x >> 13) & 3))) + +#define WM8650_BITS_TO_FREQ(r, m, d1, d2) \ + (r * m / (d1 * (1 << d2))) + +#define WM8650_BITS_TO_VAL(m, d1, d2) \ + ((d2 << 13) | (d1 << 10) | (m & 0x3FF)) + + +static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, + u32 *multiplier, u32 *prediv) +{ + unsigned long tclk; + + /* sanity check */ + if ((rate < parent_rate * 4) || (rate > parent_rate * 62)) { + pr_err("%s: requested rate out of range\n", __func__); + *multiplier = 0; + *prediv = 1; + return; + } + if (rate <= parent_rate * 31) + /* use the prediv to double the resolution */ + *prediv = 2; + else + *prediv = 1; + + *multiplier = rate / (parent_rate / *prediv); + tclk = (parent_rate / *prediv) * *multiplier; + + if (tclk != rate) + pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, + rate, tclk); +} + +static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, + u32 *multiplier, u32 *divisor1, u32 *divisor2) +{ + u32 mul, div1, div2; + u32 best_mul, best_div1, best_div2; + unsigned long tclk, rate_err, best_err; + + best_err = (unsigned long)-1; + + /* Find the closest match (lower or equal to requested) */ + for (div1 = 5; div1 >= 3; div1--) + for (div2 = 3; div2 >= 0; div2--) + for (mul = 3; mul <= 1023; mul++) { + tclk = parent_rate * mul / (div1 * (1 << div2)); + if (tclk > rate) + continue; + /* error will always be +ve */ + rate_err = rate - tclk; + if (rate_err == 0) { + *multiplier = mul; + *divisor1 = div1; + *divisor2 = div2; + return; + } + + if (rate_err < best_err) { + best_err = rate_err; + best_mul = mul; + best_div1 = div1; + best_div2 = div2; + } + } + + /* if we got here, it wasn't an exact match */ + pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, + rate - best_err); + *multiplier = mul; + *divisor1 = div1; + *divisor2 = div2; +} + +static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + u32 mul, div1, div2; + u32 pll_val; + unsigned long flags = 0; + + /* sanity check */ + + switch (pll->type) { + case PLL_TYPE_VT8500: + vt8500_find_pll_bits(rate, parent_rate, &mul, &div1); + pll_val = VT8500_BITS_TO_VAL(mul, div1); + break; + case PLL_TYPE_WM8650: + wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); + pll_val = WM8650_BITS_TO_VAL(mul, div1, div2); + break; + default: + pr_err("%s: invalid pll type\n", __func__); + return 0; + } + + spin_lock_irqsave(pll->lock, flags); + + vt8500_pmc_wait_busy(); + writel(pll_val, pll->reg); + vt8500_pmc_wait_busy(); + + spin_unlock_irqrestore(pll->lock, flags); + + return 0; +} + +static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_pll *pll = to_clk_pll(hw); + u32 mul, div1, div2; + long round_rate; + + switch (pll->type) { + case PLL_TYPE_VT8500: + vt8500_find_pll_bits(rate, *prate, &mul, &div1); + round_rate = VT8500_BITS_TO_FREQ(*prate, mul, div1); + break; + case PLL_TYPE_WM8650: + wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2); + round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2); + break; + default: + round_rate = 0; + } + + return round_rate; +} + +static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + u32 pll_val = readl(pll->reg); + unsigned long pll_freq; + + switch (pll->type) { + case PLL_TYPE_VT8500: + pll_freq = parent_rate * VT8500_PLL_MUL(pll_val); + pll_freq /= VT8500_PLL_DIV(pll_val); + break; + case PLL_TYPE_WM8650: + pll_freq = parent_rate * WM8650_PLL_MUL(pll_val); + pll_freq /= WM8650_PLL_DIV(pll_val); + break; + default: + pll_freq = 0; + } + + return pll_freq; +} + +const struct clk_ops vtwm_pll_ops = { + .round_rate = vtwm_pll_round_rate, + .set_rate = vtwm_pll_set_rate, + .recalc_rate = vtwm_pll_recalc_rate, +}; + +static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) +{ + u32 reg; + struct clk *clk; + struct clk_pll *pll_clk; + const char *clk_name = node->name; + const char *parent_name; + struct clk_init_data init; + int rc; + + rc = of_property_read_u32(node, "reg", ®); + if (WARN_ON(rc)) + return; + + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); + if (WARN_ON(!pll_clk)) + return; + + pll_clk->reg = pmc_base + reg; + pll_clk->lock = &_lock; + pll_clk->type = pll_type; + + of_property_read_string(node, "clock-output-names", &clk_name); + + init.name = clk_name; + init.ops = &vtwm_pll_ops; + init.flags = 0; + parent_name = of_clk_get_parent_name(node, 0); + init.parent_names = &parent_name; + init.num_parents = 1; + + pll_clk->hw.init = &init; + + clk = clk_register(NULL, &pll_clk->hw); + if (WARN_ON(IS_ERR(clk))) { + kfree(pll_clk); + return; + } + rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); +} + + +/* Wrappers for initialization functions */ + +static void __init vt8500_pll_init(struct device_node *node) +{ + vtwm_pll_clk_init(node, PLL_TYPE_VT8500); +} + +static void __init wm8650_pll_init(struct device_node *node) +{ + vtwm_pll_clk_init(node, PLL_TYPE_WM8650); +} + +static const __initconst struct of_device_id clk_match[] = { + { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, + { .compatible = "via,vt8500-pll-clock", .data = vt8500_pll_init, }, + { .compatible = "wm,wm8650-pll-clock", .data = wm8650_pll_init, }, + { .compatible = "via,vt8500-device-clock", + .data = vtwm_device_clk_init, }, + { /* sentinel */ } +}; + +void __init vtwm_clk_init(void __iomem *base) +{ + if (!base) + return; + + pmc_base = base; + + of_clk_init(clk_match); +} diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ba7926f5c099..a00b828b1643 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -183,6 +183,12 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_VT8500 + bool "VIA/Wondermedia SoC GPIO Support" + depends on ARCH_VT8500 + help + Say yes here to support the VT8500/WM8505/WM8650 GPIO controller. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 153caceeb053..a288142ad998 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o +obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c new file mode 100644 index 000000000000..bcd8e4aa7c7d --- /dev/null +++ b/drivers/gpio/gpio-vt8500.c @@ -0,0 +1,316 @@ +/* drivers/gpio/gpio-vt8500.c + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * Based on arch/arm/mach-vt8500/gpio.c: + * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_device.h> + +/* + We handle GPIOs by bank, each bank containing up to 32 GPIOs covered + by one set of registers (although not all may be valid). + + Because different SoC's have different register offsets, we pass the + register offsets as data in vt8500_gpio_dt_ids[]. + + A value of NO_REG is used to indicate that this register is not + supported. Only used for ->en at the moment. +*/ + +#define NO_REG 0xFFFF + +/* + * struct vt8500_gpio_bank_regoffsets + * @en: offset to enable register of the bank + * @dir: offset to direction register of the bank + * @data_out: offset to the data out register of the bank + * @data_in: offset to the data in register of the bank + * @ngpio: highest valid pin in this bank + */ + +struct vt8500_gpio_bank_regoffsets { + unsigned int en; + unsigned int dir; + unsigned int data_out; + unsigned int data_in; + unsigned char ngpio; +}; + +struct vt8500_gpio_data { + unsigned int num_banks; + struct vt8500_gpio_bank_regoffsets banks[]; +}; + +#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \ +{ \ + .en = __en, \ + .dir = __dir, \ + .data_out = __out, \ + .data_in = __in, \ + .ngpio = __ngpio, \ +} + +static struct vt8500_gpio_data vt8500_data = { + .num_banks = 7, + .banks = { + VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), + VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), + VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), + VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), + VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), + VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), + VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), + }, +}; + +static struct vt8500_gpio_data wm8505_data = { + .num_banks = 10, + .banks = { + VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), + VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), + VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), + VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16), + VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25), + VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5), + VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), + VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), + VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), + VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), + }, +}; + +/* + * No information about which bits are valid so we just make + * them all available until its figured out. + */ +static struct vt8500_gpio_data wm8650_data = { + .num_banks = 9, + .banks = { + VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32), + VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32), + VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32), + VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32), + VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32), + VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32), + VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), + VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), + VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), + }, +}; + +struct vt8500_gpio_chip { + struct gpio_chip chip; + + const struct vt8500_gpio_bank_regoffsets *regs; + void __iomem *base; +}; + + +#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) + +static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + u32 val; + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + if (vt8500_chip->regs->en == NO_REG) + return 0; + + val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); + val |= BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); + + return 0; +} + +static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + u32 val; + + if (vt8500_chip->regs->en == NO_REG) + return; + + val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en); + val &= ~BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en); +} + +static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); + val &= ~BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); + + return 0; +} + +static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir); + val |= BIT(offset); + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir); + + if (value) { + val = readl_relaxed(vt8500_chip->base + + vt8500_chip->regs->data_out); + val |= BIT(offset); + writel_relaxed(val, vt8500_chip->base + + vt8500_chip->regs->data_out); + } + return 0; +} + +static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >> + offset) & 1; +} + +static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); + + u32 val = readl_relaxed(vt8500_chip->base + + vt8500_chip->regs->data_out); + if (value) + val |= BIT(offset); + else + val &= ~BIT(offset); + + writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out); +} + +static int vt8500_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + /* bank if specificed in gpiospec->args[0] */ + if (flags) + *flags = gpiospec->args[2]; + + return gpiospec->args[1]; +} + +static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, + const struct vt8500_gpio_data *data) +{ + struct vt8500_gpio_chip *vtchip; + struct gpio_chip *chip; + int i; + int pin_cnt = 0; + + vtchip = devm_kzalloc(&pdev->dev, + sizeof(struct vt8500_gpio_chip) * data->num_banks, + GFP_KERNEL); + if (!vtchip) { + pr_err("%s: failed to allocate chip memory\n", __func__); + return -ENOMEM; + } + + for (i = 0; i < data->num_banks; i++) { + vtchip[i].base = base; + vtchip[i].regs = &data->banks[i]; + + chip = &vtchip[i].chip; + + chip->of_xlate = vt8500_of_xlate; + chip->of_gpio_n_cells = 3; + chip->of_node = pdev->dev.of_node; + + chip->request = vt8500_gpio_request; + chip->free = vt8500_gpio_free; + chip->direction_input = vt8500_gpio_direction_input; + chip->direction_output = vt8500_gpio_direction_output; + chip->get = vt8500_gpio_get_value; + chip->set = vt8500_gpio_set_value; + chip->can_sleep = 0; + chip->base = pin_cnt; + chip->ngpio = data->banks[i].ngpio; + + pin_cnt += data->banks[i].ngpio; + + gpiochip_add(chip); + } + return 0; +} + +static struct of_device_id vt8500_gpio_dt_ids[] = { + { .compatible = "via,vt8500-gpio", .data = &vt8500_data, }, + { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, }, + { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, }, + { /* Sentinel */ }, +}; + +static int __devinit vt8500_gpio_probe(struct platform_device *pdev) +{ + void __iomem *gpio_base; + struct device_node *np; + const struct of_device_id *of_id = + of_match_device(vt8500_gpio_dt_ids, &pdev->dev); + + if (!of_id) { + dev_err(&pdev->dev, "Failed to find gpio controller\n"); + return -ENODEV; + } + + np = pdev->dev.of_node; + if (!np) { + dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); + return -EFAULT; + } + + gpio_base = of_iomap(np, 0); + if (!gpio_base) { + dev_err(&pdev->dev, "Unable to map GPIO registers\n"); + of_node_put(np); + return -ENOMEM; + } + + vt8500_add_chips(pdev, gpio_base, of_id->data); + + return 0; +} + +static struct platform_driver vt8500_gpio_driver = { + .probe = vt8500_gpio_probe, + .driver = { + .name = "vt8500-gpio", + .owner = THIS_MODULE, + .of_match_table = vt8500_gpio_dt_ids, + }, +}; + +module_platform_driver(vt8500_gpio_driver); + +MODULE_DESCRIPTION("VT8500 GPIO Driver"); +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids); diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 9e94fb147c26..07bf19364a74 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -23,6 +23,7 @@ #include <linux/bcd.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/of.h> /* * Register definitions @@ -302,12 +303,18 @@ static int __devexit vt8500_rtc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id wmt_dt_ids[] = { + { .compatible = "via,vt8500-rtc", }, + {} +}; + static struct platform_driver vt8500_rtc_driver = { .probe = vt8500_rtc_probe, .remove = __devexit_p(vt8500_rtc_remove), .driver = { .name = "vt8500-rtc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wmt_dt_ids), }, }; @@ -315,5 +322,5 @@ module_platform_driver(vt8500_rtc_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:vt8500-rtc"); diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 2be006fb3da0..205d4cf4a063 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/of.h> /* * UART Register offsets @@ -76,6 +77,8 @@ #define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) #define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) +#define VT8500_MAX_PORTS 6 + struct vt8500_port { struct uart_port uart; char name[16]; @@ -83,6 +86,13 @@ struct vt8500_port { unsigned int ier; }; +/* + * we use this variable to keep track of which ports + * have been allocated as we can't use pdev->id in + * devicetree + */ +static unsigned long vt8500_ports_in_use; + static inline void vt8500_write(struct uart_port *port, unsigned int val, unsigned int off) { @@ -431,7 +441,7 @@ static int vt8500_verify_port(struct uart_port *port, return 0; } -static struct vt8500_port *vt8500_uart_ports[4]; +static struct vt8500_port *vt8500_uart_ports[VT8500_MAX_PORTS]; static struct uart_driver vt8500_uart_driver; #ifdef CONFIG_SERIAL_VT8500_CONSOLE @@ -548,7 +558,9 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) { struct vt8500_port *vt8500_port; struct resource *mmres, *irqres; + struct device_node *np = pdev->dev.of_node; int ret; + int port; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -559,16 +571,46 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) if (!vt8500_port) return -ENOMEM; + if (np) + port = of_alias_get_id(np, "serial"); + if (port > VT8500_MAX_PORTS) + port = -1; + else + port = -1; + + if (port < 0) { + /* calculate the port id */ + port = find_first_zero_bit(&vt8500_ports_in_use, + sizeof(vt8500_ports_in_use)); + } + + if (port > VT8500_MAX_PORTS) + return -ENODEV; + + /* reserve the port id */ + if (test_and_set_bit(port, &vt8500_ports_in_use)) { + /* port already in use - shouldn't really happen */ + return -EBUSY; + } + vt8500_port->uart.type = PORT_VT8500; vt8500_port->uart.iotype = UPIO_MEM; vt8500_port->uart.mapbase = mmres->start; vt8500_port->uart.irq = irqres->start; vt8500_port->uart.fifosize = 16; vt8500_port->uart.ops = &vt8500_uart_pops; - vt8500_port->uart.line = pdev->id; + vt8500_port->uart.line = port; vt8500_port->uart.dev = &pdev->dev; vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - vt8500_port->uart.uartclk = 24000000; + + vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); + if (vt8500_port->clk) { + vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); + } else { + /* use the default of 24Mhz if not specified and warn */ + pr_warn("%s: serial clock source not specified\n", __func__); + vt8500_port->uart.uartclk = 24000000; + } snprintf(vt8500_port->name, sizeof(vt8500_port->name), "VT8500 UART%d", pdev->id); @@ -579,7 +621,7 @@ static int __devinit vt8500_serial_probe(struct platform_device *pdev) goto err; } - vt8500_uart_ports[pdev->id] = vt8500_port; + vt8500_uart_ports[port] = vt8500_port; uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart); @@ -603,12 +645,18 @@ static int __devexit vt8500_serial_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id wmt_dt_ids[] = { + { .compatible = "via,vt8500-uart", }, + {} +}; + static struct platform_driver vt8500_platform_driver = { .probe = vt8500_serial_probe, .remove = __devexit_p(vt8500_serial_remove), .driver = { .name = "vt8500_serial", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wmt_dt_ids), }, }; @@ -642,4 +690,4 @@ module_exit(vt8500_serial_exit); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); MODULE_DESCRIPTION("Driver for vt8500 serial device"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0217f7415ef5..b66d951b8e32 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1788,7 +1788,7 @@ config FB_AU1200 config FB_VT8500 bool "VT8500 LCD Driver" - depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_VT8500 + depends on (FB = y) && ARM && ARCH_VT8500 select FB_WMT_GE_ROPS select FB_SYS_IMAGEBLIT help @@ -1797,11 +1797,11 @@ config FB_VT8500 config FB_WM8505 bool "WM8505 frame buffer support" - depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_WM8505 + depends on (FB = y) && ARM && ARCH_VT8500 select FB_WMT_GE_ROPS select FB_SYS_IMAGEBLIT help - This is the framebuffer driver for WonderMedia WM8505 + This is the framebuffer driver for WonderMedia WM8505/WM8650 integrated LCD controller. source "drivers/video/geode/Kconfig" diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 2a5fe6ede845..d24595cd0c9b 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -35,6 +35,13 @@ #include "vt8500lcdfb.h" #include "wmt_ge_rops.h" +#ifdef CONFIG_OF +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/memblock.h> +#endif + + #define to_vt8500lcd_info(__info) container_of(__info, \ struct vt8500lcd_info, fb) @@ -270,15 +277,21 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev) { struct vt8500lcd_info *fbi; struct resource *res; - struct vt8500fb_platform_data *pdata = pdev->dev.platform_data; void *addr; int irq, ret; + struct fb_videomode of_mode; + struct device_node *np; + u32 bpp; + dma_addr_t fb_mem_phys; + unsigned long fb_mem_len; + void *fb_mem_virt; + ret = -ENOMEM; fbi = NULL; - fbi = kzalloc(sizeof(struct vt8500lcd_info) + sizeof(u32) * 16, - GFP_KERNEL); + fbi = devm_kzalloc(&pdev->dev, sizeof(struct vt8500lcd_info) + + sizeof(u32) * 16, GFP_KERNEL); if (!fbi) { dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); ret = -ENOMEM; @@ -333,9 +346,45 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev) goto failed_free_res; } - fbi->fb.fix.smem_start = pdata->video_mem_phys; - fbi->fb.fix.smem_len = pdata->video_mem_len; - fbi->fb.screen_base = pdata->video_mem_virt; + np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); + if (!np) { + pr_err("%s: No display description in Device Tree\n", __func__); + ret = -EINVAL; + goto failed_free_res; + } + + /* + * This code is copied from Sascha Hauer's of_videomode helper + * and can be replaced with a call to the helper once mainlined + */ + ret = 0; + ret |= of_property_read_u32(np, "hactive", &of_mode.xres); + ret |= of_property_read_u32(np, "vactive", &of_mode.yres); + ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); + ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); + ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); + ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); + ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); + ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); + ret |= of_property_read_u32(np, "bpp", &bpp); + if (ret) { + pr_err("%s: Unable to read display properties\n", __func__); + goto failed_free_res; + } + of_mode.vmode = FB_VMODE_NONINTERLACED; + + /* try allocating the framebuffer */ + fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); + fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, + GFP_KERNEL); + if (!fb_mem_virt) { + pr_err("%s: Failed to allocate framebuffer\n", __func__); + return -ENOMEM; + }; + + fbi->fb.fix.smem_start = fb_mem_phys; + fbi->fb.fix.smem_len = fb_mem_len; + fbi->fb.screen_base = fb_mem_virt; fbi->palette_size = PAGE_ALIGN(512); fbi->palette_cpu = dma_alloc_coherent(&pdev->dev, @@ -370,10 +419,11 @@ static int __devinit vt8500lcd_probe(struct platform_device *pdev) goto failed_free_irq; } - fb_videomode_to_var(&fbi->fb.var, &pdata->mode); - fbi->fb.var.bits_per_pixel = pdata->bpp; - fbi->fb.var.xres_virtual = pdata->xres_virtual; - fbi->fb.var.yres_virtual = pdata->yres_virtual; + fb_videomode_to_var(&fbi->fb.var, &of_mode); + + fbi->fb.var.xres_virtual = of_mode.xres; + fbi->fb.var.yres_virtual = of_mode.yres * 2; + fbi->fb.var.bits_per_pixel = bpp; ret = vt8500lcd_set_par(&fbi->fb); if (ret) { @@ -448,12 +498,18 @@ static int __devexit vt8500lcd_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id via_dt_ids[] = { + { .compatible = "via,vt8500-fb", }, + {} +}; + static struct platform_driver vt8500lcd_driver = { .probe = vt8500lcd_probe, .remove = __devexit_p(vt8500lcd_remove), .driver = { .owner = THIS_MODULE, .name = "vt8500-lcd", + .of_match_table = of_match_ptr(via_dt_ids), }, }; @@ -461,4 +517,5 @@ module_platform_driver(vt8500lcd_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, via_dt_ids); diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index c8703bd61b74..ec4742442103 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c @@ -28,6 +28,9 @@ #include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/wait.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/memblock.h> #include <mach/vt8500fb.h> @@ -59,8 +62,12 @@ static int wm8505fb_init_hw(struct fb_info *info) writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR); writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR1); - /* Set in-memory picture format to RGB 32bpp */ - writel(0x1c, fbi->regbase + WMT_GOVR_COLORSPACE); + /* + * Set in-memory picture format to RGB + * 0x31C sets the correct color mode (RGB565) for WM8650 + * Bit 8+9 (0x300) are ignored on WM8505 as reserved + */ + writel(0x31c, fbi->regbase + WMT_GOVR_COLORSPACE); writel(1, fbi->regbase + WMT_GOVR_COLORSPACE1); /* Virtual buffer size */ @@ -127,6 +134,18 @@ static int wm8505fb_set_par(struct fb_info *info) info->var.blue.msb_right = 0; info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.line_length = info->var.xres_virtual << 2; + } else if (info->var.bits_per_pixel == 16) { + info->var.red.offset = 11; + info->var.red.length = 5; + info->var.red.msb_right = 0; + info->var.green.offset = 5; + info->var.green.length = 6; + info->var.green.msb_right = 0; + info->var.blue.offset = 0; + info->var.blue.length = 5; + info->var.blue.msb_right = 0; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.xres_virtual << 1; } wm8505fb_set_timing(info); @@ -246,16 +265,20 @@ static int __devinit wm8505fb_probe(struct platform_device *pdev) struct wm8505fb_info *fbi; struct resource *res; void *addr; - struct vt8500fb_platform_data *pdata; int ret; - pdata = pdev->dev.platform_data; + struct fb_videomode of_mode; + struct device_node *np; + u32 bpp; + dma_addr_t fb_mem_phys; + unsigned long fb_mem_len; + void *fb_mem_virt; ret = -ENOMEM; fbi = NULL; - fbi = kzalloc(sizeof(struct wm8505fb_info) + sizeof(u32) * 16, - GFP_KERNEL); + fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) + + sizeof(u32) * 16, GFP_KERNEL); if (!fbi) { dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); ret = -ENOMEM; @@ -305,21 +328,58 @@ static int __devinit wm8505fb_probe(struct platform_device *pdev) goto failed_free_res; } - fb_videomode_to_var(&fbi->fb.var, &pdata->mode); + np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); + if (!np) { + pr_err("%s: No display description in Device Tree\n", __func__); + ret = -EINVAL; + goto failed_free_res; + } + + /* + * This code is copied from Sascha Hauer's of_videomode helper + * and can be replaced with a call to the helper once mainlined + */ + ret = 0; + ret |= of_property_read_u32(np, "hactive", &of_mode.xres); + ret |= of_property_read_u32(np, "vactive", &of_mode.yres); + ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); + ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); + ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); + ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); + ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); + ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); + ret |= of_property_read_u32(np, "bpp", &bpp); + if (ret) { + pr_err("%s: Unable to read display properties\n", __func__); + goto failed_free_res; + } + + of_mode.vmode = FB_VMODE_NONINTERLACED; + fb_videomode_to_var(&fbi->fb.var, &of_mode); fbi->fb.var.nonstd = 0; fbi->fb.var.activate = FB_ACTIVATE_NOW; fbi->fb.var.height = -1; fbi->fb.var.width = -1; - fbi->fb.var.xres_virtual = pdata->xres_virtual; - fbi->fb.var.yres_virtual = pdata->yres_virtual; - fbi->fb.var.bits_per_pixel = pdata->bpp; - fbi->fb.fix.smem_start = pdata->video_mem_phys; - fbi->fb.fix.smem_len = pdata->video_mem_len; - fbi->fb.screen_base = pdata->video_mem_virt; - fbi->fb.screen_size = pdata->video_mem_len; + /* try allocating the framebuffer */ + fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); + fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, + GFP_KERNEL); + if (!fb_mem_virt) { + pr_err("%s: Failed to allocate framebuffer\n", __func__); + return -ENOMEM; + }; + + fbi->fb.var.xres_virtual = of_mode.xres; + fbi->fb.var.yres_virtual = of_mode.yres * 2; + fbi->fb.var.bits_per_pixel = bpp; + + fbi->fb.fix.smem_start = fb_mem_phys; + fbi->fb.fix.smem_len = fb_mem_len; + fbi->fb.screen_base = fb_mem_virt; + fbi->fb.screen_size = fb_mem_len; if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { dev_err(&pdev->dev, "Failed to allocate color map\n"); @@ -395,12 +455,18 @@ static int __devexit wm8505fb_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id wmt_dt_ids[] = { + { .compatible = "wm,wm8505-fb", }, + {} +}; + static struct platform_driver wm8505fb_driver = { .probe = wm8505fb_probe, .remove = __devexit_p(wm8505fb_remove), .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, + .of_match_table = of_match_ptr(wmt_dt_ids), }, }; @@ -408,4 +474,5 @@ module_platform_driver(wm8505fb_driver); MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_dt_ids); diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c index 55be3865015b..ba025b4c7d09 100644 --- a/drivers/video/wmt_ge_rops.c +++ b/drivers/video/wmt_ge_rops.c @@ -158,12 +158,18 @@ static int __devexit wmt_ge_rops_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id wmt_dt_ids[] = { + { .compatible = "wm,prizm-ge-rops", }, + { /* sentinel */ } +}; + static struct platform_driver wmt_ge_rops_driver = { .probe = wmt_ge_rops_probe, .remove = __devexit_p(wmt_ge_rops_remove), .driver = { .owner = THIS_MODULE, .name = "wmt_ge_rops", + .of_match_table = of_match_ptr(wmt_dt_ids), }, }; @@ -172,4 +178,5 @@ module_platform_driver(wmt_ge_rops_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); MODULE_DESCRIPTION("Accelerators for raster operations using " "WonderMedia Graphics Engine"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_dt_ids); |