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:
Olof Johansson 2012-09-23 21:51:39 -07:00
commit db404e72bb
51 changed files with 2294 additions and 1587 deletions

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

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -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>;
};

View 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>;
};

View 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 */
};

View 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>;
};

View File

@ -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>;
};

View 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>;
};

View 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>;
};

View File

@ -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

View 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 */
};
};
};

View 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>;
};

View 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>;
};

View File

@ -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.

View 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 */
};
};
};
};

View 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>;
};
};
};

View 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 */
};
};
};
};

View 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>;
};
};
};

View 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 */
};
};
};
};

View 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>;
};
};
};

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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
}

View File

@ -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

View File

@ -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);
}

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
};

View 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

View File

@ -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

View File

@ -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
View 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", &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);
}

View File

@ -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

View File

@ -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
View 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);

View File

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

View File

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

View File

@ -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"

View File

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

View File

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

View File

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