mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
Update arch-vt8500 and drivers to device tree and
remove existing non-dt code. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJQXBatAAoJEAKiPfwuf9N/VZoIAI7PKNwakjM/KDiVzytwqZ+U h9kkjYW4ra8MH+jpjFQqvSyIJ3U+t016xqW3ZbqRuZBDgH0I7Gax7QoAZ/ljPlpG RAKl2l9WVPiBSwCESTpvR5lafBLklk6fL0Z267qIxDGld6YBiWHvTKIh1zDmeCWW hgDeWtcb1M61VlPrj9nPnCze66h2dUk+QSxaCodv7co5kzb0Q4S7U64BCs0hGe01 kkdoUwnBjdeK0cUhDAJAP1vRyk04N16+H7yp4npmKhv/blKVc3MIRjg1iBV78ncd Kke/G1B9TJRpNTXdySYnsDQpaCWNSAryKXKkdxP0gh6MW8CMKYc1mdKYcEP3Tk8= =xG1+ -----END PGP SIGNATURE----- Merge tag 'vt8500-for-next' of git://git.code.sf.net/p/linuxwmt/code into next/dt From Tony Prisk: Update arch-vt8500 and drivers to device tree and remove existing non-dt code. * tag 'vt8500-for-next' of git://git.code.sf.net/p/linuxwmt/code: arm: vt8500: Update arch-vt8500 to devicetree support. arm: vt8500: gpio: Devicetree support for arch-vt8500 arm: vt8500: doc: Add device tree bindings for arch-vt8500 devices arm: vt8500: clk: Add Common Clock Framework support video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb serial: vt8500: Add devicetree support for vt8500-serial rtc: vt8500: Add devicetree support for vt8500-rtc arm: vt8500: Add device tree files for VIA/Wondermedia SoC's Resolved add/change conflict in drivers/clk/Makefile. Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
db404e72bb
51 changed files with 2294 additions and 1587 deletions
14
Documentation/devicetree/bindings/arm/vt8500.txt
Normal file
14
Documentation/devicetree/bindings/arm/vt8500.txt
Normal file
|
@ -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";
|
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
72
Documentation/devicetree/bindings/clock/vt8500.txt
Normal file
72
Documentation/devicetree/bindings/clock/vt8500.txt
Normal file
|
@ -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>;
|
||||
};
|
24
Documentation/devicetree/bindings/gpio/gpio-vt8500.txt
Normal file
24
Documentation/devicetree/bindings/gpio/gpio-vt8500.txt
Normal file
|
@ -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 */
|
||||
};
|
15
Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt
Normal file
15
Documentation/devicetree/bindings/rtc/via,vt8500-rtc.txt
Normal file
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
15
Documentation/devicetree/bindings/usb/platform-uhci.txt
Normal file
15
Documentation/devicetree/bindings/usb/platform-uhci.txt
Normal file
|
@ -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>;
|
||||
};
|
15
Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
Normal file
15
Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
Normal file
|
@ -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>;
|
||||
};
|
|
@ -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
|
||||
|
|
62
Documentation/devicetree/bindings/video/via,vt8500-fb.txt
Normal file
62
Documentation/devicetree/bindings/video/via,vt8500-fb.txt
Normal file
|
@ -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 */
|
||||
};
|
||||
};
|
||||
};
|
13
Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt
Normal file
13
Documentation/devicetree/bindings/video/wm,prizm-ge-rops.txt
Normal file
|
@ -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>;
|
||||
};
|
23
Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
Normal file
23
Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
Normal file
|
@ -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>;
|
||||
};
|
|
@ -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.
|
||||
|
|
36
arch/arm/boot/dts/vt8500-bv07.dts
Normal file
36
arch/arm/boot/dts/vt8500-bv07.dts
Normal file
|
@ -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 */
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
116
arch/arm/boot/dts/vt8500.dtsi
Normal file
116
arch/arm/boot/dts/vt8500.dtsi
Normal file
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
36
arch/arm/boot/dts/wm8505-ref.dts
Normal file
36
arch/arm/boot/dts/wm8505-ref.dts
Normal file
|
@ -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 */
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
143
arch/arm/boot/dts/wm8505.dtsi
Normal file
143
arch/arm/boot/dts/wm8505.dtsi
Normal file
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
36
arch/arm/boot/dts/wm8650-mid.dts
Normal file
36
arch/arm/boot/dts/wm8650-mid.dts
Normal file
|
@ -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 */
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
147
arch/arm/boot/dts/wm8650.dtsi
Normal file
147
arch/arm/boot/dts/wm8650.dtsi
Normal file
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
28
arch/arm/mach-vt8500/common.h
Normal file
28
arch/arm/mach-vt8500/common.h
Normal file
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 < wmt_nr_irqs; i++) {
|
||||
/* Disable all interrupts and route them to IRQ */
|
||||
writeb(0x00, ic_regbase + VT8500_IC_DCTR + i);
|
||||
|
||||
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");
|
||||
for (i = 0; i < 64; i++) {
|
||||
/* Disable all interrupts and route them to IRQ */
|
||||
writeb(VT8500_INT_DISABLE | ICDC_IRQ,
|
||||
base + VT8500_ICDC + i);
|
||||
}
|
||||
}
|
||||
|
||||
void __init wm8505_init_irq(void)
|
||||
static int vt8500_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
unsigned int i;
|
||||
irq_set_chip_and_handler(virq, &vt8500_irq_chip, handle_level_irq);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
printk(KERN_ERR "Unable to remap the Interrupt Controller registers, not enabling IRQs!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
};
|
||||
|
|
196
arch/arm/mach-vt8500/vt8500.c
Normal file
196
arch/arm/mach-vt8500/vt8500.c
Normal file
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
510
drivers/clk/clk-vt8500.c
Normal file
510
drivers/clk/clk-vt8500.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
316
drivers/gpio/gpio-vt8500.c
Normal file
316
drivers/gpio/gpio-vt8500.c
Normal file
|
@ -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);
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue