summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Konovalov <andrey.konovalov@linaro.org>2013-09-06 23:28:00 +0400
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-09-06 23:28:00 +0400
commitdadafb94ba81815cf23ca28bd59614f68b74a24e (patch)
tree64aac7cabbe7fea9680cedbabd0ff182e7fcf52e
parent0a7875e02eafe840fb4cdc009c795f2637cc7c72 (diff)
parent8c03a2759bb93416165fc842221da78494346944 (diff)
Merge branch 'tracking-samslt-all' into merge-linux-linaroll-20130906.0
-rw-r--r--Documentation/devicetree/bindings/clock/exynos5250-clock.txt15
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt2
-rw-r--r--Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt167
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--Makefile5
-rw-r--r--arch/arm/boot/dts/exynos5.dtsi5
-rw-r--r--arch/arm/boot/dts/exynos5250-arndale.dts151
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts137
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi39
-rw-r--r--arch/arm/configs/arndale_android_defconfig139
-rw-r--r--arch/arm/configs/arndale_ubuntu_defconfig228
-rw-r--r--arch/arm/mach-exynos/headsmp.S114
-rw-r--r--arch/arm/mach-exynos/hotplug.c8
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h4
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-pmu.h3
-rw-r--r--drivers/ata/Kconfig22
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/sata_exynos.c307
-rw-r--r--drivers/ata/sata_exynos_phy.c296
-rw-r--r--drivers/ata/sata_exynos_phy.h32
-rw-r--r--drivers/ata/sata_phy.c147
-rw-r--r--drivers/ata/sata_phy.h30
-rw-r--r--drivers/clk/samsung/clk-exynos4.c40
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c133
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c86
-rw-r--r--drivers/clk/samsung/clk-pll.c339
-rw-r--r--drivers/clk/samsung/clk-pll.h38
-rw-r--r--drivers/clk/samsung/clk.h53
-rw-r--r--drivers/clocksource/exynos_mct.c6
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c38
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c38
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c114
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c32
-rw-r--r--drivers/gpu/drm/exynos/regs-hdmi.h4
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c68
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c16
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c7
-rw-r--r--drivers/net/usb/asix_devices.c32
-rw-r--r--drivers/tty/serial/samsung.c29
-rw-r--r--drivers/video/exynos/exynos_dp_core.c66
-rwxr-xr-x[-rw-r--r--]drivers/video/exynos/exynos_mipi_dsi.c639
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi_common.c3
-rwxr-xr-x[-rw-r--r--]drivers/video/exynos/s6e8ax0.c921
-rw-r--r--firmware/edid-1920x1080.fwbin0 -> 128 bytes
-rw-r--r--include/linux/printk.h1
-rw-r--r--include/linux/scatterlist.h2
-rw-r--r--include/uapi/linux/v4l2-controls.h4
-rw-r--r--include/video/exynos_mipi_dsim.h29
-rw-r--r--init/main.c1
-rw-r--r--init/version.c3
-rw-r--r--linaro/configs/arndale.conf31
-rw-r--r--sound/soc/codecs/Kconfig3
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/i2s_stub.c74
-rw-r--r--sound/soc/samsung/Kconfig9
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/dma.c3
-rw-r--r--sound/soc/samsung/idma.c2
-rw-r--r--sound/soc/samsung/smdk_i2s_stub.c244
62 files changed, 4290 insertions, 692 deletions
diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 781a6276adf7..4810e4f62699 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -24,6 +24,7 @@ clock which they consume.
----------------------------
fin_pll 1
+ sclk_vpll 2
[Clock Gate for Special Clocks]
@@ -59,6 +60,9 @@ clock which they consume.
sclk_spi0 154
sclk_spi1 155
sclk_spi2 156
+ div_i2s1 157
+ div_i2s2 158
+ sclk_hdmiphy 159
[Peripheral Clock Gates]
@@ -154,7 +158,16 @@ clock which they consume.
dsim0 341
dp 342
mixer 343
- hdmi 345
+ hdmi 344
+ smmu_mixer 345
+
+
+ [Clock Muxes]
+
+ Clock ID
+ ----------------------------
+ mout_hdmi 1024
+
Example 1: An example of a clock controller node is listed below.
diff --git a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
index 296eb4536129..278de8e64bbf 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
@@ -10,6 +10,8 @@ Required properties:
inside HDMIPHY block found on several samsung SoCs
(d) "samsung, exynos5440-i2c", for s3c2440-like i2c used
on EXYNOS5440 which does not need GPIO configuration.
+ (e) "samsung, exynos5-sata-phy-i2c", for s3c2440-like i2c used as
+ a host to SATA PHY controller on an internal bus.
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
diff --git a/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt b/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
new file mode 100644
index 000000000000..7460b1ff85c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos/mipi-dsi.txt
@@ -0,0 +1,167 @@
+* Samsung Exynos MIPI-DSI bindings
+
+Properties for MIPI-DSI node ::
+===============================
+- compatible: should be "samsung,exynos-mipi"
+
+- reg: should contain mipi-dsi physical address location and length.
+
+- interrupts: should contain mipi-dsi interrupt number
+
+- enabled: Describes whether MIPI DSI got enabled in uboot
+
+- mipi-lcd: phandle to lcd specific information. It can be anything
+ specific to lcd driver.
+
+- mipi-phy: phandle to D-PHY node.
+
+- mipi-config: subnode for mipi config information
+ - auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse
+ - eot_disable: enable or disable EoT packet in HS mode
+ - auto_vertical_cnt: specifies auto vertical count mode.
+ In Video mode, the vertical line transition uses line counter
+ configured by VSA, VBP, and Vertical resolution. If this bit is
+ set to '1', the line counter does not use VSA and VBP registers.
+ In command mode, this property is ignored.
+ - hse: set horizontal sync event mode.
+ In VSYNC pulse and Vporch area, MIPI DSI master transfers only
+ HSYNC start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+ This bit transfers HSYNC end packet in VSYNC pulse and Vporch
+ area. In command mode, this property is ignored.
+ - hfp: specifies HFP disable mode.
+ If this property is set, DSI master ignores HFP area in
+ VIDEO mode. In command mode, this property is ignored.
+ - hbp: specifies HBP disable mode.
+ If this property is set, DSI master ignores HBP area in
+ VIDEO mode. In command mode, this property is ignored.
+ - hsa: specifies HSA disable mode.
+ If this property is set, DSI master ignores HSA area in
+ VIDEO mode. In command mode, this property is ignored.
+ - cmd_allow: specifies the number of horizontal lines, where command
+ packet transmission is allowed after Stable VFP period.
+ - e_interface: specifies interface to be used.(CPU or RGB interface)
+ - e_virtual_ch: specifies virtual channel number that main or
+ sub display uses.
+ - e_pixel_format: specifies pixel stream format for main or sub display.
+ - e_burst_mode: selects Burst mode in Video mode.
+ In Non-burst mode, RGB data area is filled with RGB data
+ and NULL packets, according to input bandwidth of RGB interface.
+ In Burst mode, RGB data area is filled with RGB data only.
+ - e_no_data_lane: specifies data lane count to be used by Master.
+ - e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+ DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+ - pll_stable_time: specifies the PLL Timer for stability of the
+ generated clock(System clock cycle base). If the timer value
+ goes to 0x00000000, the clock stable bit of status and interrupt
+ register is set.
+ - esc_clk: specifies escape clock frequency for getting the escape clock
+ prescaler value.
+ - stop_holding_cnt: specifies the interval value between transmitting
+ read packet(or write "set_tear_on" command) and BTA request.
+ after transmitting read packet or write "set_tear_on" command,
+ BTA requests to D-PHY automatically. this counter value
+ specifies the interval between them.
+ - bta_timeout: specifies the timer for BTA.
+ this register specifies time out from BTA request to change
+ the direction with respect to Tx escape clock.
+ - rx_timeout: specifies the timer for LP Rx mode timeout.
+ this register specifies time out on how long RxValid deasserts,
+ after RxLpdt asserts with respect to Tx escape clock.
+ - RxValid specifies Rx data valid indicator.
+ - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+ - RxValid and RxLpdt specifies signal from D-PHY.
+
+- panel-info: timing information from the panel used.
+ - lcd-htiming : xres, left_margin, right_margin, hsync-len info
+ - lcd-vtiming : yres, upper_margin, lower_margin, vsync-len info
+
+Properties for D-PHY node ::
+=============================
+ Instead of passing D-PHY related callbacks as part of platform data,
+we can pass the phy nodes to the mipi driver. Depending on the type of PHY
+settings, we can implement multiple PHY node types and corresponding
+enable/disable/reset callbacks in the driver itself. Currently we support
+only one type of PHY node.
+
+D-PHY node type1:
+------------------
+- compatible: "samsung,exynos-mipi-phy-type1"
+- reg_enable_dphy: should contain physical address location of
+ D-PHY enable register
+- mask_enable_dphy: should contain the mask for D-PHY enable register
+- reg_reset_dsim: should contain physical address location of
+ D-PHY DSIM reset register
+- mask_reset_dsim: should contain the mask for D-PHY DSIM reset register
+
+MIPI-LCD node ::
+=================
+ Apart from the following three properties, driver specific
+properties can be sent through this node. The following example sends
+some more properties for driver's use.
+
+- lcd-name: name of the device to use with this device
+- id: id of device to be registered (default -1 in case not specified)
+- bus-id: bus id for identifing connected bus and this bus id should be
+ same as id of mipi_dsim_device (default -1 incase not specified)
+
+Example:
+--------
+ mipi_lcd: mipi-lcd@toshiba {
+ lcd-name = "tc358764";
+ id = <0>;
+ enabled = <1>;
+ reset-delay = <120>;
+ power-on-delay = <25>;
+ power-off-delay = <200>;
+ gpio-poweron = <&gpx1 5 0 0 0>;
+ };
+
+ mipi_dsim_phy: mipi-phy@exynos5250 {
+ compatible = "samsung-exynos,mipi-phy-type1";
+ reg_enable_dphy = <0x10040714>;
+ mask_enable_dphy = <0x00000001>;
+ reg_reset_dsim = <0x10040714>;
+ mask_reset_dsim = <0x00000004>;
+ };
+
+ mipi_dsi_tc358764: lcd_panel_tc358764 {
+ lcd-htiming = <24 24 2 800>;
+ lcd-vtiming = <1 13 2 1280>;
+ };
+
+ mipi {
+ compatible = "samsung,exynos-mipi";
+ reg = <0x14500000 0x10000>;
+ interrupts = <0 82 0>;
+
+ mipi-lcd = <&mipi_lcd>;
+ mipi-phy = <&mipi_dsim_phy>;
+ enabled = <0>;
+
+ panel-info = <&lcd_mipi_dsi_tc358764>;
+ mipi-config {
+ e_interface = <1>;
+ e_pixel_format = <7>;
+ auto_flush = <0>;
+ eot_disable = <0>;
+ auto_vertical_cnt = <0>;
+ hse = <0>;
+ hfp = <0>;
+ hbp = <0>;
+ hsa = <0>;
+ e_no_data_lane = <3>;
+ e_byte_clk = <0>;
+ e_burst_mode = <3>;
+ p = <3>;
+ m = <115>;
+ s = <1>;
+ pll_stable_time = <500>;
+ esc_clk = <400000>;
+ stop_holding_cnt =<0x0f>;
+ bta_timeout = <0xff>;
+ rx_timeout = <0xffff>;
+ e_virtual_ch = <0>;
+ cmd_allow = <0xf>;
+ };
+
+ };
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 97247fb528cd..293d40548ca0 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1549,6 +1549,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
ltpc= [NET]
Format: <io>,<irq>,<dma>
+ mac= [NET]
+ Used ASIX drivers.
+ Example: mac=12:34:56:78:ab:cd
+
machvec= [IA-64] Force the use of a particular machine-vector
(machvec) in a generic kernel.
Example: machvec=hpzx1_swiotlb
diff --git a/Makefile b/Makefile
index fe8204be566d..df2f01e39101 100644
--- a/Makefile
+++ b/Makefile
@@ -799,7 +799,6 @@ include/config/kernel.release: include/config/auto.conf FORCE
$(Q)rm -f $@
$(Q)echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" > $@
-
# Things we need to do before we recursively start building the kernel
# or the modules are listed in "prepare".
# A multi level approach is used. prepareN is processed before prepareN-1.
@@ -849,7 +848,9 @@ define filechk_utsrelease.h
echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
exit 1; \
fi; \
- (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";)
+ (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\"; \
+ echo \#define KERNEL_GIT_ID \"$(shell \
+ git rev-parse --verify --short HEAD 2>/dev/null)\";)
endef
define filechk_version.h
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi
index f65e124c04a6..d83573a573ca 100644
--- a/arch/arm/boot/dts/exynos5.dtsi
+++ b/arch/arm/boot/dts/exynos5.dtsi
@@ -23,6 +23,11 @@
reg = <0x10000000 0x100>;
};
+ sys_reg: sysreg {
+ compatible = "samsung,exynos5-sysreg";
+ reg = <0x10050000 0x2000>;
+ };
+
combiner:interrupt-controller@10440000 {
compatible = "samsung,exynos4210-combiner";
#interrupt-cells = <2>;
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index 3937993b95f3..c3c93037eb52 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -29,6 +29,29 @@
samsung,mfc-l = <0x51000000 0x800000>;
};
+ i2s0: i2s@03830000 {
+ status = "okay";
+ };
+
+ i2s1: i2s@12D60000 {
+ status = "disabled";
+ };
+
+ i2s2: i2s@12D70000 {
+ status = "disabled";
+ };
+
+ i2s_stub: i2s-stub {
+ compatible = "linux,i2s-stub";
+ };
+
+ sound {
+ compatible = "samsung,smdk-i2s-stub";
+
+ samsung,i2s-controller = <&i2s0>;
+ samsung,audio-codec = <&i2s_stub>;
+ };
+
i2c@12C60000 {
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <20000>;
@@ -291,7 +314,13 @@
};
i2c@12C80000 {
- status = "disabled";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ hdmiddc@50 {
+ compatible = "samsung,exynos5-hdmiddc";
+ reg = <0x50>;
+ };
};
i2c@12C90000 {
@@ -314,10 +343,31 @@
status = "disabled";
};
+ i2c@12CE0000 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ hdmiphy@38 {
+ compatible = "samsung,exynos5-hdmiphy";
+ reg = <0x38>;
+ };
+ };
+
i2c@121D0000 {
- status = "disabled";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <40000>;
+ samsung,i2c-slave-addr = <0x38>;
+
+ sata-phy {
+ compatible = "samsung,sata-phy";
+ reg = <0x38>;
+ };
};
+ sata@122F0000 {
+ samsung,sata-freq = <66>;
+ };
+
dwmmc_0: dwmmc0@12200000 {
num-slots = <1>;
supports-highspeed;
@@ -448,6 +498,22 @@
hub-connect = <&gpd1 7 1>;
};
+ vdd11:fixed-regulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd11-supply";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ vdd18:fixed-regulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd18-supply";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
@@ -462,6 +528,11 @@
samsung,color-depth = <1>;
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_hpd>;
+ lcd_bl_gpio = <&gpb2 0 1>;
+ lcd_en_gpio = <&gpx1 5 1>;
};
fimd: fimd@14400000 {
@@ -469,7 +540,7 @@
native-mode = <&timing0>;
timing0: timing@0 {
/* 2560x1600 DP panel */
- clock-frequency = <50000>;
+ clock-frequency = <266000000>;
hactive = <2560>;
vactive = <1600>;
hfront-porch = <48>;
@@ -479,6 +550,80 @@
vfront-porch = <8>;
vsync-len = <6>;
};
+ timing1: timing@1 {
+ /* 800x1280 */
+ clock-frequency = <266000000>;
+ hactive = <800>;
+ vactive = <1280>;
+ hfront-porch = <11>;
+ hback-porch = <3>;
+ hsync-len = <2>;
+ vback-porch = <11>;
+ vfront-porch = <3>;
+ vsync-len = <2>;
+ };
+ };
+ };
+
+ lcd_mipi_dsi_s6e8ax0: lcd_panel_s6e8ax0 {
+ lcd-htiming = <11 3 2 800>;
+ lcd-vtiming = <11 3 2 1280>;
+ };
+
+ mipi_lcd_s6e8ax0: mipi-lcd@s6e8ax0 {
+ compatible = "s6e8ax0";
+ lcd-name = "s6e8ax0";
+ lcd_enabled = <1>;
+ reset-delay = <50>;
+ power-on-delay = <120>;
+ power-off-delay = <200>;
+ gpio-reset = <&gpx1 5 0 0 0>;
+ gpio-power = <&gpx3 0 0 0 0>;
+ gpio-bl = <&gpb2 0 0 0 0>;
+ };
+
+ mipi_dsim_phy: mipi-phy@exynos5250 {
+ compatible = "samsung-exynos,mipi-phy-type1";
+ reg_enable_dphy = <0x10040714>;
+ mask_enable_dphy = <0x00000001>;
+ reg_reset_dsim = <0x10040714>;
+ mask_reset_dsim = <0x00000004>;
+ };
+
+ mipi-dsim {
+ status = "okay";
+ mipi-lcd = <&mipi_lcd_s6e8ax0>;
+ mipi-phy = <&mipi_dsim_phy>;
+ enabled = <0>;
+ panel-info = <&lcd_mipi_dsi_s6e8ax0>;
+ vdd11-supply = <&vdd11>;
+ vdd18-supply = <&vdd18>;
+ vdd3-supply = <&vdd18>;
+ vci-supply = <&vdd18>;
+
+ mipi-config {
+ e_interface = <1>;
+ e_pixel_format = <7>;
+ auto_flush = <0>;
+ eot_disable = <0>;
+ auto_vertical_cnt = <0>;
+ hse = <0>;
+ hfp = <0>;
+ hbp = <0>;
+ hsa = <0>;
+ e_no_data_lane = <3>;
+ e_byte_clk = <0>;
+ e_burst_mode = <1>;
+ p = <3>;
+ m = <115>;
+ s = <1>;
+ pll_stable_time = <500>;
+ esc_clk = <7000000>;
+ stop_holding_cnt =<0x0fff>;
+ bta_timeout = <0xff>;
+ rx_timeout = <0xffff>;
+ e_virtual_ch = <0>;
+ cmd_allow = <0x1>;
};
};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 49f18c24a576..874c91a092a3 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -61,6 +61,22 @@
regulator-always-on;
};
+ vdd11:fixed-regulator@3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd11-supply";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ vdd18:fixed-regulator@4 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd18-supply";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
i2c@12C70000 {
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <20000>;
@@ -260,21 +276,49 @@
pinctrl-names = "default";
pinctrl-0 = <&dp_hpd>;
- };
-
- display-timings {
- native-mode = <&timing0>;
- timing0: timing@0 {
- /* 1280x800 */
- clock-frequency = <50000>;
- hactive = <1280>;
- vactive = <800>;
- hfront-porch = <4>;
- hback-porch = <4>;
- hsync-len = <4>;
- vback-porch = <4>;
- vfront-porch = <4>;
- vsync-len = <4>;
+ lcd_bl_gpio = <&gpb2 0 1>;
+ lcd_en_gpio = <&gpx1 5 1>;
+ };
+
+ fimd {
+ display-timings {
+ native-mode = <&timing1>;
+ timing0: timing@0 {
+ /* 1280x800 */
+ clock-frequency = <50000>;
+ hactive = <1280>;
+ vactive = <800>;
+ hfront-porch = <4>;
+ hback-porch = <4>;
+ hsync-len = <4>;
+ vback-porch = <4>;
+ vfront-porch = <4>;
+ vsync-len = <4>;
+ };
+ timing1: timing@1 {
+ /* 800x1280 */
+ clock-frequency = <266000000>;
+ hactive = <800>;
+ vactive = <1280>;
+ hfront-porch = <11>;
+ hback-porch = <3>;
+ hsync-len = <2>;
+ vback-porch = <11>;
+ vfront-porch = <3>;
+ vsync-len = <2>;
+ };
+ timing2: timing@2 {
+ /* 2560x1600 */
+ clock-frequency = <266000000>;
+ hactive = <2560>;
+ vactive = <1600>;
+ hfront-porch = <48>;
+ hback-porch = <80>;
+ hsync-len = <32>;
+ vback-porch = <16>;
+ vfront-porch = <8>;
+ vsync-len = <6>;
+ };
};
};
@@ -284,4 +328,67 @@
clock-frequency = <24000000>;
};
};
+
+ lcd_mipi_dsi_s6e8ax0: lcd_panel_s6e8ax0 {
+ lcd-htiming = <11 3 2 800>;
+ lcd-vtiming = <11 3 2 1280>;
+ };
+
+ mipi_lcd_s6e8ax0: mipi-lcd@s6e8ax0 {
+ compatible = "s6e8ax0";
+ lcd-name = "s6e8ax0";
+ lcd_enabled = <1>;
+ reset-delay = <50>;
+ power-on-delay = <120>;
+ power-off-delay = <200>;
+ gpio-reset = <&gpx1 5 0 0 0>;
+ gpio-power = <&gpx3 0 0 0 0>;
+ gpio-bl = <&gpb2 0 0 0 0>;
+ };
+
+ mipi_dsim_phy: mipi-phy@exynos5250 {
+ compatible = "samsung-exynos,mipi-phy-type1";
+ reg_enable_dphy = <0x10040714>;
+ mask_enable_dphy = <0x00000001>;
+ reg_reset_dsim = <0x10040714>;
+ mask_reset_dsim = <0x00000004>;
+ };
+
+ mipi-dsim {
+ status = "okay";
+ mipi-lcd = <&mipi_lcd_s6e8ax0>;
+ mipi-phy = <&mipi_dsim_phy>;
+ enabled = <0>;
+ panel-info = <&lcd_mipi_dsi_s6e8ax0>;
+
+ vdd11-supply = <&vdd11>;
+ vdd18-supply = <&vdd18>;
+ vdd3-supply = <&vdd18>;
+ vci-supply = <&vdd18>;
+
+ mipi-config {
+ e_interface = <1>;
+ e_pixel_format = <7>;
+ auto_flush = <0>;
+ eot_disable = <0>;
+ auto_vertical_cnt = <0>;
+ hse = <0>;
+ hfp = <0>;
+ hbp = <0>;
+ hsa = <0>;
+ e_no_data_lane = <3>;
+ e_byte_clk = <0>;
+ e_burst_mode = <1>;
+ p = <3>;
+ m = <115>;
+ s = <1>;
+ pll_stable_time = <500>;
+ esc_clk = <7000000>;
+ stop_holding_cnt =<0x0fff>;
+ bta_timeout = <0xff>;
+ rx_timeout = <0xffff>;
+ e_virtual_ch = <0>;
+ cmd_allow = <0x1>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index ef57277fc38f..6cd0ef7f6bc7 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -205,15 +205,24 @@
sata@122F0000 {
compatible = "samsung,exynos5-sata-ahci";
+ samsung,exynos-sata-phy = <&phy0>;
reg = <0x122F0000 0x1ff>;
interrupts = <0 115 0>;
clocks = <&clock 277>, <&clock 143>;
clock-names = "sata", "sclk_sata";
};
- sata-phy@12170000 {
+ phy0:sata-phy@12170000 {
compatible = "samsung,exynos5-sata-phy";
reg = <0x12170000 0x1ff>;
+ clocks = <&clock 287>;
+ clock-names = "sata_phyctrl";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ sataphy-pmu {
+ reg = <0x10040724 0x4>;
+ };
};
i2c_0: i2c@12C60000 {
@@ -602,16 +611,24 @@
compatible = "samsung,exynos4212-hdmi";
reg = <0x14530000 0x70000>;
interrupts = <0 95 0>;
- clocks = <&clock 333>, <&clock 136>, <&clock 137>,
- <&clock 333>, <&clock 333>;
+ clocks = <&clock 344>, <&clock 136>, <&clock 137>,
+ <&clock 159>, <&clock 1024>;
clock-names = "hdmi", "sclk_hdmi", "sclk_pixel",
- "sclk_hdmiphy", "hdmiphy";
+ "sclk_hdmiphy", "mout_hdmi";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ phy-power-control {
+ reg = <0x10040700 0x04>;
+ };
};
mixer {
compatible = "samsung,exynos5250-mixer";
reg = <0x14450000 0x10000>;
interrupts = <0 94 0>;
+ clocks = <&clock 343>, <&clock 136>;
+ clock-names = "mixer", "sclk_hdmi";
};
dp-controller {
@@ -636,7 +653,17 @@
reg = <0x14400000 0x40000>;
interrupt-names = "fifo", "vsync", "lcd_sys";
interrupts = <18 4>, <18 5>, <18 6>;
- clocks = <&clock 133>, <&clock 339>;
- clock-names = "sclk_fimd", "fimd";
+ clocks = <&clock 133>, <&clock 339>, <&clock 1025>, <&clock 2>;
+ clock-names = "sclk_fimd", "fimd", "mout_fimd", "sclk_mout_fimd";
+ samsung,sys-reg = <&sys_reg>;
+ };
+
+ mipi-dsim {
+ status = "disabled";
+ compatible = "samsung,exynos-mipidsim";
+ reg = <0x14500000 0x10000>;
+ interrupts = <0 82 0>;
+ clocks = <&clock 341>;
+ clock-names = "dsim0";
};
};
diff --git a/arch/arm/configs/arndale_android_defconfig b/arch/arm/configs/arndale_android_defconfig
new file mode 100644
index 000000000000..60f627e0eca9
--- /dev/null
+++ b/arch/arm/configs/arndale_android_defconfig
@@ -0,0 +1,139 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+CONFIG_ARCH_EXYNOS=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=2
+# CONFIG_ARCH_EXYNOS4 is not set
+CONFIG_ARCH_EXYNOS5=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init= mem=256M"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IPV6=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_IPV6_SIT=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_SATA_EXYNOS=y
+CONFIG_NETDEVICES=y
+CONFIG_AX88796=y
+CONFIG_AX88796_93CX6=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_USB_USBNET=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C_GPIO=y
+# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_EXYNOS_THERMAL=y
+CONFIG_MFD_SEC_CORE=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_S5P=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_EXYNOS=y
+CONFIG_USB_STORAGE=y
+CONFIG_SAMSUNG_USBPHY=y
+CONFIG_USB_GADGET=y
+CONFIG_MMC=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_MMC_DW_EXYNOS=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_PERSISTENT_TRACER=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ANDROID_SWITCH=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_DEBUG=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_S3C_UART2=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/arndale_ubuntu_defconfig b/arch/arm/configs/arndale_ubuntu_defconfig
new file mode 100644
index 000000000000..4714cea21083
--- /dev/null
+++ b/arch/arm/configs/arndale_ubuntu_defconfig
@@ -0,0 +1,228 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_ARCH_EXYNOS=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=2
+CONFIG_ARCH_EXYNOS5=y
+CONFIG_ARM_LPAE=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_SMT=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_NR_CPUS=2
+CONFIG_THUMB2_KERNEL=y
+CONFIG_HIGHMEM=y
+# CONFIG_COMPACTION is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_SECCOMP=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init= mem=256M"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_NF_NAT_IPV4=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_NF_NAT_IPV6=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_EXTRA_FIRMWARE="edid-1920x1080.fw"
+CONFIG_CMA=y
+CONFIG_CMA_SIZE_MBYTES=128
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_OOPS=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_NAND=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_SATA_EXYNOS=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=y
+CONFIG_AX88796=y
+CONFIG_AX88796_93CX6=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_DM9601=y
+CONFIG_USB_NET_MCS7830=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_EXYNOS_THERMAL=y
+CONFIG_MFD_SEC_CORE=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_DRM=y
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_EXYNOS=y
+CONFIG_DRM_EXYNOS_DMABUF=y
+CONFIG_DRM_EXYNOS_FIMD=y
+CONFIG_DRM_EXYNOS_HDMI=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_EXYNOS_VIDEO=y
+CONFIG_EXYNOS_MIPI_DSI=y
+CONFIG_EXYNOS_LCD_S6E8AX0=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SAMSUNG=y
+CONFIG_SND_SOC_SMDK_I2S_STUB=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_S5P=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_EXYNOS=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_HOST=y
+CONFIG_USB_PHY=y
+CONFIG_SAMSUNG_USB2PHY=y
+CONFIG_SAMSUNG_USB3PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_MMC_DW_EXYNOS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_S3C=y
+CONFIG_PWM=y
+CONFIG_PWM_SAMSUNG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
+CONFIG_BTRFS_FS=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V2 is not set
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_FUNCTION_TRACER=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_DEBUG_USER=y
+CONFIG_SECURITY=y
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_DEFAULT_SECURITY_APPARMOR=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=y
diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S
index cdd9d91e9933..348c61509e62 100644
--- a/arch/arm/mach-exynos/headsmp.S
+++ b/arch/arm/mach-exynos/headsmp.S
@@ -12,12 +12,105 @@
*/
#include <linux/linkage.h>
#include <linux/init.h>
+#include <asm/assembler.h>
/*
* exynos4 specific entry point for secondary CPUs. This provides
* a "holding pen" into which all secondary cores are held until we're
* ready for them to initialise.
*/
+
+.arch_extension sec
+.arch_extension virt
+.text
+
+.align 5
+/* We use the same vector table for Hyp and Monitor mode, since
+ * we will only use each once and they don't overlap.
+ */
+mon_vectors:
+ W(b) . /* reset */
+ W(b) . /* undef */
+ W(b) 2f /* smc */
+ W(b) . /* pabt */
+ W(b) . /* dabt */
+ W(b) 1f /* hyp */
+ W(b) . /* irq */
+ W(b) . /* fiq */
+
+/* Return directly back to the caller without leaving Hyp mode: */
+1: mrs lr, elr_hyp
+ mov pc, lr
+
+/* In monitor mode, set up HVBAR and SCR then return to caller in NS-SVC. */
+2:
+ mrc p15, 0, r1, c1, c1, 0 @ SCR
+ /*
+ * Set SCR.NS=1(needed for setting HVBAR and also returning to NS state)
+ * .IRQ,FIQ,EA=0 (don't take aborts/exceptions to Monitor mode)
+ * .FW,AW=1 (CPSR.A,F modifiable in NS state)
+ * .nET=0 (early termination OK)
+ * .SCD=0 (SMC in NS mode OK, so we can call secure firmware)
+ * .HCE=1 (HVC does Hyp call)
+ */
+ bic r1, r1, #0x07f
+ ldr r2, =0x131
+ orr r1, r1, r2
+ mcr p15, 0, r2, c1, c1, 0 @ SCR
+ isb
+ ldr r2, =mon_vectors
+
+
+ adr r4, 1f
+ ldmia r4, {r5}
+ sub r4, r4, r5
+ add r2, r2, r4
+
+ mcr p15, 4, r2, c12, c0, 0 @ set HVBAR
+
+ THUMB( mrc p15, 4, r2, c1, c0, 0 ) @ ctrl register
+ THUMB( orr r2, r2, #1 << 30 ) @ HSCTLR.TE (Thumb exceptions)
+ THUMB( mcr p15, 4, r2, c1, c0, 0 )
+ THUMB( isb)
+
+ /* ...and return to calling code in NS state */
+ movs pc, lr
+
+
+ .globl monitor_init
+monitor_init:
+ ldr ip, =mon_vectors
+
+ adr r4, 1f
+ ldmia r4, {r5}
+ sub r4, r4, r5
+ add ip, ip, r4
+ mcr p15, 0, ip, c12, c0, 1
+
+ THUMB( mrc p15, 0, r1, c1, c0, 0 ) @ ctrl register
+ THUMB( orr r1, r1, #1 << 30 ) @ SCTLR.TE (Thumb exceptions)
+ THUMB( mcr p15, 0, r1, c1, c0, 0 )
+ THUMB( isb )
+
+ mov pc, lr
+
+ /* Try to go into NS-SVC: void enter_ns(void); */
+ .globl enter_ns
+enter_ns:
+ smc #0
+ mov pc, lr
+
+ /* void enter_hyp(void); */
+ .globl enter_hyp
+enter_hyp:
+ /* Now we're in NS-SVC, make a Hyp call to get into Hyp mode */
+ mov r0, lr
+ mov r1, sp
+ hvc #0
+ /* We will end up here in NS-Hyp. */
+ mov sp, r1
+ mov pc, r0
+
ENTRY(exynos4_secondary_startup)
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #15
@@ -29,6 +122,27 @@ pen: ldr r7, [r6]
cmp r7, r0
bne pen
+ ldr r1, =__boot_cpu_mode
+ add r1, r1, r4
+ ldr r2, [r1]
+ mrs r0, cpsr
+ ands r0, r0, #MODE_MASK
+ subs r1, r0, r2
+ beq 3f
+ subs r2, r2, #HYP_MODE
+ bne 3f
+
+ /* Setting NSACR to allow coprocessor access from non-secure mode */
+ mrc p15, 0, r0, c1, c1, 2
+ movw r1, #0x3fff
+ orr r0, r0, r1
+ mcr p15, 0, r0, c1, c1, 2
+5:
+ bl monitor_init
+ bl enter_ns
+ bl enter_hyp
+
+3:
/*
* we've been released from the holding pen: secondary_stack
* should now contain the SVC stack for this core
diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c
index af90cfa2f826..cce2b0d960e7 100644
--- a/arch/arm/mach-exynos/hotplug.c
+++ b/arch/arm/mach-exynos/hotplug.c
@@ -98,13 +98,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
if (cpu == 1)
__raw_writel(0, S5P_ARM_CORE1_CONFIGURATION);
- /*
- * here's the WFI
- */
- asm(".word 0xe320f003\n"
- :
- :
- : "memory", "cc");
+ wfi();
if (pen_release == cpu_logical_map(cpu)) {
/*
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 7b046b59d9ec..a5df67b15718 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -60,6 +60,10 @@
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_L2CC 0x10502000
+#define EXYNOS5_PA_SATA_PHY_CTRL 0x12170000
+#define EXYNOS5_PA_SATA_PHY_I2C 0x121D0000
+#define EXYNOS5_PA_SATA_BASE 0x122F0000
+
#define EXYNOS4_PA_SROMC 0x12570000
#define EXYNOS5_PA_SROMC 0x12250000
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 57344b7e98ce..66ffff8069f1 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -370,4 +370,7 @@
#define EXYNOS5_OPTION_USE_RETENTION (1 << 4)
+/* Only for EXYNOS5250 */
+#define EXYNOS5_SATA_PHY_CONTROL S5P_PMUREG(0x0724)
+
#endif /* __ASM_ARCH_REGS_PMU_H */
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4e737728aee2..c81fe31b3da6 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -97,6 +97,28 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config SATA_PHY
+ bool "SATA PHY Framework"
+ default n
+ help
+ This option enables the SATA PHY utility framework APIs.
+ The framework acts as an interface between the SATA device
+ and the PHY device. The SATA PHY device registers itself
+ with the framework through the APIs provided and the SATA
+ device finds and requests for an appropriate PHY device.
+
+config SATA_EXYNOS
+ bool "Exynos SATA AHCI support"
+ select I2C
+ select HAVE_S3C2410_I2C
+ select I2C_S3C2410
+ select SATA_PHY
+ help
+ This option enables support for Exynos AHCI Serial ATA
+ controllers.
+
+ If unsure, say N.
+
config AHCI_IMX
tristate "Freescale i.MX AHCI SATA support"
depends on SATA_AHCI_PLATFORM && MFD_SYSCON
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 46518c622460..a4e5cf56d475 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
+obj-$(CONFIG_SATA_PHY) += sata_phy.o
+obj-$(CONFIG_SATA_EXYNOS) += sata_exynos.o sata_exynos_phy.o libahci.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
# SFF w/ custom DMA
diff --git a/drivers/ata/sata_exynos.c b/drivers/ata/sata_exynos.c
new file mode 100644
index 000000000000..1dcfb2c8d0de
--- /dev/null
+++ b/drivers/ata/sata_exynos.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - SATA controller platform driver wrapper
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include "ahci.h"
+#include "sata_phy.h"
+
+#define MHZ (1000 * 1000)
+#define DEFERED 1
+#define NO_PORT 0
+
+static const struct ata_port_info ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+};
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT("ahci_platform"),
+};
+
+struct exynos_sata {
+ struct clk *sclk;
+ struct clk *clk;
+ int irq;
+ unsigned int freq;
+ struct sata_phy *phy[];
+};
+
+static int exynos_sata_parse_dt(struct device_node *np,
+ struct exynos_sata *sata)
+{
+ if (!np)
+ return -EINVAL;
+
+ return of_property_read_u32(np, "samsung,sata-freq",
+ &sata->freq);
+}
+
+static int exynos_sata_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_port_info pi = ahci_port_info;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ahci_host_priv *hpriv;
+ struct exynos_sata *sata;
+ struct ata_host *host;
+ struct device_node *of_node_phy = NULL;
+ static int flag = 0, port_init = NO_PORT;
+ int n_ports, i, ret;
+
+ sata = devm_kzalloc(dev, sizeof(*sata), GFP_KERNEL);
+ if (!sata) {
+ dev_err(dev, "can't alloc sata\n");
+ return -ENOMEM;
+ }
+
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ dev_err(dev, "can't alloc ahci_host_priv\n");
+ return -ENOMEM;
+ }
+
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ sata->irq = irq_of_parse_and_map(dev->of_node, 0);
+ if (sata->irq <= 0) {
+ dev_err(dev, "irq not specified\n");
+ return -EINVAL;
+ }
+
+ hpriv->mmio = of_iomap(dev->of_node, 0);
+ if (!hpriv->mmio) {
+ dev_err(dev, "failed to map IO\n");
+ return -ENOMEM;
+ }
+
+ ret = exynos_sata_parse_dt(dev->of_node, sata);
+ if (ret < 0) {
+ dev_err(dev, "failed to get frequency for sata ctrl\n");
+ goto err_iomap;
+ }
+
+ sata->sclk = devm_clk_get(dev, "sclk_sata");
+ if (IS_ERR(sata->sclk)) {
+ dev_err(dev, "failed to get sclk_sata\n");
+ ret = PTR_ERR(sata->sclk);
+ goto err_iomap;
+ }
+
+ ret = clk_prepare_enable(sata->sclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable source clk\n");
+ goto err_iomap;
+ }
+
+ ret = clk_set_rate(sata->sclk, sata->freq * MHZ);
+ if (ret < 0) {
+ dev_err(dev, "failed to set clk frequency\n");
+ goto err_clkstrt;
+ }
+
+ sata->clk = devm_clk_get(dev, "sata");
+ if (IS_ERR(sata->clk)) {
+ dev_err(dev, "failed to get sata clock\n");
+ ret = PTR_ERR(sata->clk);
+ goto err_clkstrt;
+ }
+
+ ret = clk_prepare_enable(sata->clk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable source clk\n");
+ goto err_clkstrt;
+ }
+
+ ahci_save_initial_config(dev, hpriv, 0, 0);
+
+ /* prepare host */
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ ahci_set_em_messages(hpriv, &pi);
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+ if (!host) {
+ ret = -ENOMEM;
+ goto err_clken;
+ }
+
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ pr_info(KERN_INFO
+ "ahci: SSS flag set, parallel bus scan disabled\n");
+
+ if (pi.flags & ATA_FLAG_EM)
+ ahci_reset_em(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ of_node_phy = of_parse_phandle(dev->of_node,
+ "samsung,exynos-sata-phy", i);
+ if (!of_node_phy) {
+ dev_err(dev,
+ "phandle of phy not found for port %d\n", i);
+ break;
+ }
+
+ sata->phy[i] = sata_get_phy(of_node_phy);
+ if (IS_ERR(sata->phy[i])) {
+ if (PTR_ERR(sata->phy[i]) == -EBUSY)
+ continue;
+ dev_err(dev,
+ "failed to get sata phy for port %d\n", i);
+ if (flag != DEFERED) {
+ flag = DEFERED ;
+ return -EPROBE_DEFER;
+ } else
+ continue;
+
+ }
+ /* Initialize the PHY */
+ ret = sata_init_phy(sata->phy[i]);
+ if (ret < 0) {
+ if (ret == -EPROBE_DEFER) {
+ if (flag != DEFERED) {
+ flag = DEFERED ;
+ sata_put_phy(sata->phy[i]);
+ return -EPROBE_DEFER;
+ } else {
+ continue;
+ }
+ } else {
+ dev_err(dev,
+ "failed to initialize sata phy for port %d\n",
+ i);
+ sata_put_phy(sata->phy[i]);
+ }
+
+ }
+
+ /* set enclosure management message type */
+ if (ap->flags & ATA_FLAG_EM)
+ ap->em_message_type = hpriv->em_msg_type;
+
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+
+ port_init++;
+ }
+
+ if (port_init == NO_PORT)
+ goto err_initphy;
+
+ ret = ahci_reset_controller(host);
+ if (ret)
+ goto err_rst;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "platform");
+
+ ret = ata_host_activate(host, sata->irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_platform_sht);
+ if (ret)
+ goto err_rst;
+
+ platform_set_drvdata(pdev, sata);
+
+ return 0;
+
+ err_rst:
+ for (i = 0; i < host->n_ports; i++)
+ sata_shutdown_phy(sata->phy[i]);
+
+ err_initphy:
+ for (i = 0; i < host->n_ports; i++)
+ sata_put_phy(sata->phy[i]);
+
+ err_clken:
+ clk_disable_unprepare(sata->clk);
+
+ err_clkstrt:
+ clk_disable_unprepare(sata->sclk);
+
+ err_iomap:
+ iounmap(hpriv->mmio);
+
+ return ret;
+}
+
+static int exynos_sata_remove(struct platform_device *pdev)
+{
+ unsigned int i;
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct exynos_sata *sata = platform_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv =
+ (struct ahci_host_priv *)host->private_data;
+
+ ata_host_detach(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ sata_shutdown_phy(sata->phy[i]);
+ sata_put_phy(sata->phy[i]);
+ }
+ iounmap(hpriv->mmio);
+
+ return 0;
+}
+
+static const struct of_device_id ahci_of_match[] = {
+ { .compatible = "samsung,exynos5-sata-ahci", },
+};
+
+MODULE_DEVICE_TABLE(of, ahci_of_match);
+
+static struct platform_driver exynos_sata_driver = {
+ .probe = exynos_sata_probe,
+ .remove = exynos_sata_remove,
+ .driver = {
+ .name = "exynos-sata",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_of_match,
+ },
+};
+
+module_platform_driver(exynos_sata_driver);
+
+MODULE_DESCRIPTION("EXYNOS SATA DRIVER");
+MODULE_AUTHOR("Vasanth Ananthan, <vasanth.a@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/sata_exynos_phy.c b/drivers/ata/sata_exynos_phy.c
new file mode 100644
index 000000000000..e9417097ffb2
--- /dev/null
+++ b/drivers/ata/sata_exynos_phy.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - SATA PHY controller driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/ahci_platform.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include <plat/cpu.h>
+#include <plat/irqs.h>
+
+#include <mach/map.h>
+#include <mach/regs-pmu.h>
+
+#include "sata_phy.h"
+#include "sata_exynos_phy.h"
+
+#define SATA_TIME_LIMIT 1000
+
+static struct i2c_client *i2c_client;
+
+static struct i2c_driver sataphy_i2c_driver;
+
+struct exynos_sata_phy {
+ void __iomem *mmio;
+ void __iomem *pmureg;
+ struct clk *clk;
+ struct device *dev;
+ struct sata_phy phy;
+};
+
+static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 status)
+{
+ if ((readl(base + reg) & checkbit) == status)
+ return true;
+ else
+ return false;
+}
+
+static bool wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
+ u32 status)
+{
+ unsigned long timeout = jiffies + usecs_to_jiffies(1000);
+
+ while (time_before(jiffies, timeout)) {
+ if (sata_is_reg(base, reg, checkbit, status))
+ return true;
+ }
+
+ return false;
+}
+
+static int exynos_sataphy_parse_dt(struct device *dev,
+ struct exynos_sata_phy *phy)
+{
+ struct device_node *sataphy_pmu;
+
+ sataphy_pmu = of_get_child_by_name(dev->of_node, "sataphy-pmu");
+ if (!sataphy_pmu) {
+ dev_err(dev,
+ "PMU control register for sata-phy not specified\n");
+ return -ENODEV;
+ }
+
+ phy->pmureg = of_iomap(sataphy_pmu, 0);
+
+ of_node_put(sataphy_pmu);
+
+ if (!phy->pmureg) {
+ dev_err(dev, "Can't get sata-phy pmu control register\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
+static int exynos_sataphy_init(struct sata_phy *phy)
+{
+ int ret;
+ u32 val;
+
+ /* Values to be written to enable 40 bits interface */
+ u8 buf[] = { 0x3A, 0x0B };
+
+ struct exynos_sata_phy *sata_phy;
+
+ if (!i2c_client)
+ return -EPROBE_DEFER;
+
+ sata_phy = container_of(phy, struct exynos_sata_phy, phy);
+
+ ret = clk_prepare_enable(sata_phy->clk);
+ if (ret < 0) {
+ dev_err(phy->dev, "failed to enable source clk\n");
+ return ret;
+ }
+
+ if (sata_is_reg(sata_phy->mmio , EXYNOS5_SATA_CTRL0,
+ CTRL0_P0_PHY_CALIBRATED, CTRL0_P0_PHY_CALIBRATED))
+ return 0;
+
+ writel(SATA_PHY_PMU_EN, sata_phy->pmureg);
+
+ val = 0;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET);
+ val |= 0xFF;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET);
+ val |= LINK_RESET;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM);
+ val &= ~PHCTRLM_REF_RATE;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM);
+
+ /* High speed enable for Gen3 */
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM);
+ val |= PHCTRLM_HIGH_SPEED;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM);
+
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_CTRL0);
+ val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_CTRL0);
+
+ writel(0x2, sata_phy->mmio + EXYNOS5_SATA_MODE0);
+
+ ret = i2c_master_send(i2c_client, buf, sizeof(buf));
+ if (ret < 0)
+ return -ENXIO;
+
+ /* release cmu reset */
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET);
+ val &= ~RESET_CMN_RST_N;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET);
+
+ val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET);
+ val |= RESET_CMN_RST_N;
+ writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET);
+
+ if (wait_for_reg_status(sata_phy->mmio, EXYNOS5_SATA_PHSATA_STATM,
+ PHSTATM_PLL_LOCKED, 1)) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int exynos_sataphy_shutdown(struct sata_phy *phy)
+{
+
+ struct exynos_sata_phy *sata_phy;
+
+ sata_phy = container_of(phy, struct exynos_sata_phy, phy);
+ clk_disable_unprepare(sata_phy->clk);
+
+ return 0;
+}
+
+static int exynos_sata_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ i2c_client = client;
+ return 0;
+}
+
+static int exynos_sata_phy_probe(struct platform_device *pdev)
+{
+ struct exynos_sata_phy *sataphy;
+ struct device *dev = &pdev->dev;
+ int ret = 0;
+ sataphy = devm_kzalloc(dev, sizeof(struct exynos_sata_phy), GFP_KERNEL);
+ if (!sataphy) {
+ dev_err(dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ sataphy->mmio = of_iomap(dev->of_node, 0);
+ if (!sataphy->mmio) {
+ dev_err(dev, "failed to remap IO\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ ret = exynos_sataphy_parse_dt(dev, sataphy);
+ if (ret != 0)
+ goto err_iomap;
+
+ sataphy->clk = devm_clk_get(dev, "sata_phyctrl");
+ if (IS_ERR(sataphy->clk)) {
+ dev_err(dev, "failed to get clk for PHY\n");
+ ret = PTR_ERR(sataphy->clk);
+ goto err_pmu;
+ }
+
+ sataphy->phy.init = exynos_sataphy_init;
+ sataphy->phy.shutdown = exynos_sataphy_shutdown;
+ sataphy->phy.dev = dev;
+
+ ret = sata_add_phy(&sataphy->phy);
+ if (ret < 0) {
+ dev_err(dev, "PHY not registered with framework\n");
+ goto err_iomap;
+ }
+
+ ret = i2c_add_driver(&sataphy_i2c_driver);
+ if (ret < 0)
+ goto err_phy;
+
+ platform_set_drvdata(pdev, sataphy);
+
+ return ret;
+
+ err_phy:
+ sata_remove_phy(&sataphy->phy);
+
+ err_pmu:
+ iounmap(sataphy->pmureg);
+
+ err_iomap:
+ iounmap(sataphy->mmio);
+
+ return ret;
+}
+
+static int exynos_sata_phy_remove(struct platform_device *pdev)
+{
+ struct exynos_sata_phy *sataphy;
+
+ sataphy = platform_get_drvdata(pdev);
+ iounmap(sataphy->mmio);
+ i2c_del_driver(&sataphy_i2c_driver);
+ sata_remove_phy(&sataphy->phy);
+
+ return 0;
+}
+
+static const struct of_device_id sata_phy_of_match[] = {
+ { .compatible = "samsung,exynos5-sata-phy", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sata_phy_of_match);
+
+static const struct i2c_device_id phy_i2c_device_match[] = {
+ { "sata-phy", 0 },
+};
+
+MODULE_DEVICE_TABLE(of, phy_i2c_device_match);
+
+static struct platform_driver sata_phy_driver = {
+ .probe = exynos_sata_phy_probe,
+ .remove = exynos_sata_phy_remove,
+ .driver = {
+ .name = "sata-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = sata_phy_of_match,
+ },
+};
+
+static struct i2c_driver sataphy_i2c_driver = {
+ .driver = {
+ .name = "sata-phy-i2c",
+ .owner = THIS_MODULE,
+ .of_match_table = (void *)phy_i2c_device_match,
+ },
+ .probe = exynos_sata_i2c_probe,
+ .id_table = phy_i2c_device_match,
+};
+
+module_platform_driver(sata_phy_driver);
+
+MODULE_DESCRIPTION("EXYNOS SATA PHY DRIVER");
+MODULE_AUTHOR("Vasanth Ananthan, <vasanth.a@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/sata_exynos_phy.h b/drivers/ata/sata_exynos_phy.h
new file mode 100644
index 000000000000..f9889ccd9abc
--- /dev/null
+++ b/drivers/ata/sata_exynos_phy.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - SATA PHY controller definition
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#define EXYNOS5_SATA_RESET 0x4
+#define RESET_CMN_RST_N (1 << 1)
+#define LINK_RESET 0xF0000
+
+#define EXYNOS5_SATA_MODE0 0x10
+
+#define EXYNOS5_SATA_CTRL0 0x14
+#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9)
+#define CTRL0_P0_PHY_CALIBRATED (1 << 8)
+
+#define EXYNOS5_SATA_PHSATA_CTRLM 0xE0
+#define PHCTRLM_REF_RATE (1 << 1)
+#define PHCTRLM_HIGH_SPEED (1 << 0)
+
+#define EXYNOS5_SATA_PHSATA_STATM 0xF0
+#define PHSTATM_PLL_LOCKED (1 << 0)
+
+#define SATA_PHY_CON_RESET 0xF003F
+
+#define SATA_PHY_PMU_EN 0x1
+
diff --git a/drivers/ata/sata_phy.c b/drivers/ata/sata_phy.c
new file mode 100644
index 000000000000..53d441775d74
--- /dev/null
+++ b/drivers/ata/sata_phy.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * SATA PHY framework.
+ *
+ * This file provides a set of functions/interfaces for establishing
+ * communication between SATA controller and the PHY controller. A
+ * PHY controller driver registers call backs for its initialization and
+ * shutdown. The SATA controller driver finds the appropriate PHYs for
+ * its implemented ports and initialize/shutdown PHYs through the
+ * call backs provided.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include "sata_phy.h"
+
+static LIST_HEAD(phy_list);
+static DEFINE_SPINLOCK(phy_lock);
+
+struct sata_phy *sata_get_phy(struct device_node *phy_np)
+{
+ struct sata_phy *phy;
+ unsigned long flag;
+
+ spin_lock_irqsave(&phy_lock, flag);
+
+ if (list_empty(&phy_list)) {
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return ERR_PTR(-ENODEV);
+ }
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->dev->of_node == phy_np) {
+ if (phy->status == IN_USE) {
+ pr_info(KERN_INFO
+ "PHY already in use\n");
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return ERR_PTR(-EBUSY);
+ }
+
+ get_device(phy->dev);
+ phy->status = IN_USE;
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return phy;
+ }
+ }
+
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(sata_get_phy);
+
+int sata_add_phy(struct sata_phy *sataphy)
+{
+ unsigned long flag;
+ unsigned int ret = -EINVAL;
+ struct sata_phy *phy;
+
+ if (!sataphy)
+ return ret;
+
+ spin_lock_irqsave(&phy_lock, flag);
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->dev->of_node == sataphy->dev->of_node) {
+ dev_err(sataphy->dev, "PHY already exists in the list\n");
+ goto out;
+ }
+ }
+
+ sataphy->status = NOT_IN_USE;
+ list_add_tail(&sataphy->head, &phy_list);
+ ret = 0;
+
+ out:
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return ret;
+}
+EXPORT_SYMBOL(sata_add_phy);
+
+void sata_remove_phy(struct sata_phy *sataphy)
+{
+ unsigned long flag;
+ struct sata_phy *phy;
+
+ if (!sataphy)
+ return;
+
+ if (sataphy->status == IN_USE) {
+ pr_info(KERN_INFO
+ "PHY in use, cannot be removed\n");
+ return;
+ }
+
+ spin_lock_irqsave(&phy_lock, flag);
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->dev->of_node == sataphy->dev->of_node)
+ list_del(&phy->head);
+ }
+
+ spin_unlock_irqrestore(&phy_lock, flag);
+}
+EXPORT_SYMBOL(sata_remove_phy);
+
+void sata_put_phy(struct sata_phy *sataphy)
+{
+ unsigned long flag;
+
+ if (!sataphy)
+ return;
+
+ spin_lock_irqsave(&phy_lock, flag);
+
+ put_device(sataphy->dev);
+ sataphy->status = NOT_IN_USE;
+
+ spin_unlock_irqrestore(&phy_lock, flag);
+}
+EXPORT_SYMBOL(sata_put_phy);
+
+int sata_init_phy(struct sata_phy *sataphy)
+{
+ if (sataphy && sataphy->init)
+ return sataphy->init(sataphy);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(sata_init_phy);
+
+void sata_shutdown_phy(struct sata_phy *sataphy)
+{
+ if (sataphy && sataphy->shutdown)
+ sataphy->shutdown(sataphy);
+}
+EXPORT_SYMBOL(sata_shutdown_phy);
+
diff --git a/drivers/ata/sata_phy.h b/drivers/ata/sata_phy.h
new file mode 100644
index 000000000000..9ed1dbed5a11
--- /dev/null
+++ b/drivers/ata/sata_phy.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * SATA utility framework definitions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#define IN_USE 1
+#define NOT_IN_USE 0
+
+struct sata_phy {
+ int (*init) (struct sata_phy *);
+ int (*shutdown) (struct sata_phy *);
+ struct device *dev;
+ void *priv_data;
+ struct list_head head;
+ unsigned char status;
+};
+
+struct sata_phy *sata_get_phy(struct device_node *);
+int sata_add_phy(struct sata_phy *);
+void sata_remove_phy(struct sata_phy *);
+void sata_put_phy(struct sata_phy *);
+int sata_init_phy(struct sata_phy *);
+void sata_shutdown_phy(struct sata_phy *);
+
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 4e5739773c33..f1fd7144cf3c 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -17,7 +17,6 @@
#include <linux/of_address.h>
#include "clk.h"
-#include "clk-pll.h"
/* Exynos4 clock controller register offsets */
#define SRC_LEFTBUS 0x4200
@@ -97,12 +96,14 @@
#define GATE_IP_PERIL 0xc950
#define E4210_GATE_IP_PERIR 0xc960
#define GATE_BLOCK 0xc970
+#define E4X12_MPLL_LOCK 0x10008
#define E4X12_MPLL_CON0 0x10108
#define SRC_DMC 0x10200
#define SRC_MASK_DMC 0x10300
#define DIV_DMC0 0x10500
#define DIV_DMC1 0x10504
#define GATE_IP_DMC 0x10900
+#define APLL_LOCK 0x14000
#define APLL_CON0 0x14100
#define E4210_MPLL_CON0 0x14108
#define SRC_CPU 0x14200
@@ -121,6 +122,12 @@ enum exynos4_soc {
EXYNOS4X12,
};
+/* list of PLLs to be registered */
+enum exynos4_plls {
+ apll, mpll, epll, vpll,
+ nr_plls /* number of PLLs */
+};
+
/*
* Let each supported clock get a unique id. This id is used to lookup the clock
* for device tree based platforms. The clocks are categorized into three
@@ -993,6 +1000,17 @@ static __initdata struct of_device_id ext_clk_match[] = {
{},
};
+struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = {
+ [apll] = PLL_A(pll_35xx, fout_apll, "fout_apll", "fin_pll", APLL_LOCK,
+ APLL_CON0, "fout_apll", NULL),
+ [mpll] = PLL_A(pll_35xx, fout_mpll, "fout_mpll", "fin_pll",
+ E4X12_MPLL_LOCK, E4X12_MPLL_CON0, "fout_mpll", NULL),
+ [epll] = PLL_A(pll_36xx, fout_epll, "fout_epll", "fin_pll", EPLL_LOCK,
+ EPLL_CON0, "fout_epll", NULL),
+ [vpll] = PLL_A(pll_36xx, fout_vpll, "fout_vpll", "fin_pll", VPLL_LOCK,
+ VPLL_CON0, "fout_vpll", NULL),
+};
+
/* register exynos4 clocks */
void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom)
{
@@ -1029,22 +1047,16 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
reg_base + EPLL_CON0, pll_4600);
vpll = samsung_clk_register_pll46xx("fout_vpll", "mout_vpllsrc",
reg_base + VPLL_CON0, pll_4650c);
+
+ samsung_clk_add_lookup(apll, fout_apll);
+ samsung_clk_add_lookup(mpll, fout_mpll);
+ samsung_clk_add_lookup(epll, fout_epll);
+ samsung_clk_add_lookup(vpll, fout_vpll);
} else {
- apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
- reg_base + APLL_CON0);
- mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
- reg_base + E4X12_MPLL_CON0);
- epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
- reg_base + EPLL_CON0);
- vpll = samsung_clk_register_pll36xx("fout_vpll", "fin_pll",
- reg_base + VPLL_CON0);
+ samsung_clk_register_pll(exynos4_plls,
+ ARRAY_SIZE(exynos4_plls), reg_base);
}
- samsung_clk_add_lookup(apll, fout_apll);
- samsung_clk_add_lookup(mpll, fout_mpll);
- samsung_clk_add_lookup(epll, fout_epll);
- samsung_clk_add_lookup(vpll, fout_vpll);
-
samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks,
ARRAY_SIZE(exynos4_fixed_rate_clks));
samsung_clk_register_mux(exynos4_mux_clks,
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index 6f767c515ec7..0f9a957f6054 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -17,13 +17,25 @@
#include <linux/of_address.h>
#include "clk.h"
-#include "clk-pll.h"
+#define APLL_LOCK 0x0
+#define APLL_CON0 0x100
#define SRC_CPU 0x200
#define DIV_CPU0 0x500
+#define MPLL_LOCK 0x4000
+#define MPLL_CON0 0x4100
#define SRC_CORE1 0x4204
+#define CPLL_LOCK 0x10020
+#define EPLL_LOCK 0x10030
+#define VPLL_LOCK 0x10040
+#define GPLL_LOCK 0x10050
+#define CPLL_CON0 0x10120
+#define EPLL_CON0 0x10130
+#define VPLL_CON0 0x10140
+#define GPLL_CON0 0x10150
#define SRC_TOP0 0x10210
#define SRC_TOP2 0x10218
+#define SRC_TOP3 0x1021C
#define SRC_GSCL 0x10220
#define SRC_DISP1_0 0x1022c
#define SRC_MAU 0x10240
@@ -58,6 +70,8 @@
#define GATE_IP_GEN 0x10934
#define GATE_IP_FSYS 0x10944
#define GATE_IP_PERIC 0x10950
+#define BPLL_LOCK 0x20010
+#define BPLL_CON0 0x20110
#define GATE_IP_PERIS 0x10960
#define SRC_CDREX 0x20200
#define PLL_DIV2_SEL 0x20a24
@@ -75,11 +89,18 @@
* device tree files. This limitation would go away when pre-processor support
* for dtc would be available.
*/
+
+/* list of PLLs to be registered */
+enum exynos5250_plls {
+ apll, mpll, cpll, epll, vpll, gpll, bpll,
+ nr_plls /* number of PLLs */
+};
+
enum exynos5250_clks {
none,
/* core clocks */
- fin_pll,
+ fin_pll, sclk_vpll, fout_apll, fout_mpll, fout_bpll, fout_gpll, fout_cpll, fout_epll, fout_vpll,
/* gate for special clocks (sclk) */
sclk_cam_bayer = 128, sclk_cam0, sclk_cam1, sclk_gscl_wa, sclk_gscl_wb,
@@ -87,7 +108,7 @@ enum exynos5250_clks {
sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_sata, sclk_usb3,
sclk_jpeg, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_pwm,
sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2,
- div_i2s1, div_i2s2,
+ div_i2s1, div_i2s2, sclk_hdmiphy,
/* gate clocks */
gscl0 = 256, gscl1, gscl2, gscl3, gscl_wa, gscl_wb, smmu_gscl0,
@@ -99,7 +120,13 @@ enum exynos5250_clks {
spi2, i2s1, i2s2, pcm1, pcm2, pwm, spdif, ac97, hsi2c0, hsi2c1, hsi2c2,
hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1,
tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct,
- wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi,
+ wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, smmu_mixer,
+
+ /* mux clocks */
+ mout_hdmi = 1024,
+
+ /* mux clocks */
+ mout_fimd1,
nr_clks,
};
@@ -169,6 +196,7 @@ PNAME(mout_mpll_user_p) = { "fin_pll", "sclk_mpll" };
PNAME(mout_bpll_user_p) = { "fin_pll", "sclk_bpll" };
PNAME(mout_aclk166_p) = { "sclk_cpll", "sclk_mpll_user" };
PNAME(mout_aclk200_p) = { "sclk_mpll_user", "sclk_bpll_user" };
+PNAME(mout_aclk200_disp1_sub_p) = { "fin_pll", "aclk200" };
PNAME(mout_hdmi_p) = { "div_hdmi_pixel", "sclk_hdmiphy" };
PNAME(mout_usb3_p) = { "sclk_mpll_user", "sclk_cpll" };
PNAME(mout_group1_p) = { "fin_pll", "fin_pll", "sclk_hdmi27m",
@@ -197,7 +225,7 @@ struct samsung_fixed_rate_clock exynos5250_fixed_rate_ext_clks[] __initdata = {
/* fixed rate clocks generated inside the soc */
struct samsung_fixed_rate_clock exynos5250_fixed_rate_clks[] __initdata = {
- FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
+ FRATE(sclk_hdmiphy, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
FRATE(none, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000),
FRATE(none, "sclk_dptxphy", NULL, CLK_IS_ROOT, 24000000),
FRATE(none, "sclk_uhostphy", NULL, CLK_IS_ROOT, 48000000),
@@ -208,6 +236,10 @@ struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = {
FFACTOR(none, "fout_bplldiv2", "fout_bpll", 1, 2, 0),
};
+static struct samsung_mux_clock exynos5250_pll_pmux_clks[] __initdata = {
+ MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1),
+};
+
struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
MUX_A(none, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, "mout_apll"),
MUX_A(none, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1, "mout_cpu"),
@@ -215,8 +247,8 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
MUX_A(none, "sclk_mpll", mout_mpll_p, SRC_CORE1, 8, 1, "mout_mpll"),
MUX(none, "mout_bpll_fout", mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1),
MUX(none, "sclk_bpll", mout_bpll_p, SRC_CDREX, 0, 1),
- MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1),
- MUX(none, "sclk_vpll", mout_vpll_p, SRC_TOP2, 16, 1),
+ MUX_F(sclk_vpll, "sclk_vpll", mout_vpll_p, SRC_TOP2, 16, 1,
+ CLK_SET_RATE_PARENT, 0),
MUX(none, "sclk_epll", mout_epll_p, SRC_TOP2, 12, 1),
MUX(none, "sclk_cpll", mout_cpll_p, SRC_TOP2, 8, 1),
MUX(none, "sclk_mpll_user", mout_mpll_user_p, SRC_TOP2, 20, 1),
@@ -224,15 +256,18 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
MUX(none, "mout_aclk166", mout_aclk166_p, SRC_TOP0, 8, 1),
MUX(none, "mout_aclk333", mout_aclk166_p, SRC_TOP0, 16, 1),
MUX(none, "mout_aclk200", mout_aclk200_p, SRC_TOP0, 12, 1),
+ MUX(none, "mout_aclk200_disp1", mout_aclk200_disp1_sub_p,
+ SRC_TOP3, 4, 1),
MUX(none, "mout_cam_bayer", mout_group1_p, SRC_GSCL, 12, 4),
MUX(none, "mout_cam0", mout_group1_p, SRC_GSCL, 16, 4),
MUX(none, "mout_cam1", mout_group1_p, SRC_GSCL, 20, 4),
MUX(none, "mout_gscl_wa", mout_group1_p, SRC_GSCL, 24, 4),
MUX(none, "mout_gscl_wb", mout_group1_p, SRC_GSCL, 28, 4),
- MUX(none, "mout_fimd1", mout_group1_p, SRC_DISP1_0, 0, 4),
+ MUX_F(mout_fimd1, "mout_fimd1", mout_group1_p, SRC_DISP1_0, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
MUX(none, "mout_mipi1", mout_group1_p, SRC_DISP1_0, 12, 4),
MUX(none, "mout_dp", mout_group1_p, SRC_DISP1_0, 16, 4),
- MUX(none, "mout_hdmi", mout_hdmi_p, SRC_DISP1_0, 20, 1),
+ MUX(mout_hdmi, "mout_hdmi", mout_hdmi_p, SRC_DISP1_0, 20, 1),
MUX(none, "mout_audio0", mout_audio0_p, SRC_MAU, 0, 4),
MUX(none, "mout_mmc0", mout_group1_p, SRC_FSYS, 0, 4),
MUX(none, "mout_mmc1", mout_group1_p, SRC_FSYS, 4, 4),
@@ -268,7 +303,8 @@ struct samsung_div_clock exynos5250_div_clks[] __initdata = {
DIV(none, "div_cam1", "mout_cam1", DIV_GSCL, 20, 4),
DIV(none, "div_gscl_wa", "mout_gscl_wa", DIV_GSCL, 24, 4),
DIV(none, "div_gscl_wb", "mout_gscl_wb", DIV_GSCL, 28, 4),
- DIV(none, "div_fimd1", "mout_fimd1", DIV_DISP1_0, 0, 4),
+ DIV_F(none, "div_fimd1", "mout_fimd1", DIV_DISP1_0, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
DIV(none, "div_mipi1", "mout_mipi1", DIV_DISP1_0, 16, 4),
DIV(none, "div_dp", "mout_dp", DIV_DISP1_0, 24, 4),
DIV(none, "div_jpeg", "mout_jpeg", DIV_GEN, 4, 4),
@@ -325,6 +361,7 @@ struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
GATE(smmu_gscl1, "smmu_gscl1", "aclk266", GATE_IP_GSCL, 8, 0, 0),
GATE(smmu_gscl2, "smmu_gscl2", "aclk266", GATE_IP_GSCL, 9, 0, 0),
GATE(smmu_gscl3, "smmu_gscl3", "aclk266", GATE_IP_GSCL, 10, 0, 0),
+ GATE(smmu_mixer, "smmu_mixer", "mout_aclk200_disp1", GATE_IP_DISP1, 9, 0, 0),
GATE(mfc, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0),
GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0),
GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0),
@@ -461,8 +498,48 @@ struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
GATE(mie1, "mie1", "aclk200", GATE_IP_DISP1, 1, 0, 0),
GATE(dsim0, "dsim0", "aclk200", GATE_IP_DISP1, 3, 0, 0),
GATE(dp, "dp", "aclk200", GATE_IP_DISP1, 4, 0, 0),
- GATE(mixer, "mixer", "aclk200", GATE_IP_DISP1, 5, 0, 0),
- GATE(hdmi, "hdmi", "aclk200", GATE_IP_DISP1, 6, 0, 0),
+ GATE(mixer, "mixer", "mout_aclk200_disp1", GATE_IP_DISP1, 5, 0, 0),
+ GATE(hdmi, "hdmi", "mout_aclk200_disp1", GATE_IP_DISP1, 6, 0, 0),
+};
+
+static __initdata struct samsung_pll_rate_table vpll_24mhz_tbl[] = {
+ /* sorted in descending order */
+ /* PLL_36XX_RATE(rate, m, p, s, k) */
+ PLL_36XX_RATE(266000000, 266, 3, 3, 0),
+ /* Not in UM, but need for eDP on snow */
+ PLL_36XX_RATE(70500000, 94, 2, 4, 0),
+ { },
+};
+
+static __initdata struct samsung_pll_rate_table epll_24mhz_tbl[] = {
+ /* sorted in descending order */
+ /* PLL_36XX_RATE(rate, m, p, s, k) */
+ PLL_36XX_RATE(192000000, 64, 2, 2, 0),
+ PLL_36XX_RATE(180633600, 90, 3, 2, 20762),
+ PLL_36XX_RATE(180000000, 90, 3, 2, 0),
+ PLL_36XX_RATE(73728000, 98, 2, 4, 19923),
+ PLL_36XX_RATE(67737600, 90, 2, 4, 20762),
+ PLL_36XX_RATE(49152000, 98, 3, 4, 19923),
+ PLL_36XX_RATE(45158400, 90, 3, 4, 20762),
+ PLL_36XX_RATE(32768000, 131, 3, 5, 4719),
+ { },
+};
+
+struct __initdata samsung_pll_clock exynos5250_plls[nr_plls] = {
+ [apll] = PLL_A(pll_35xx, fout_apll, "fout_apll", "fin_pll", APLL_LOCK,
+ APLL_CON0, "fout_apll", NULL),
+ [mpll] = PLL_A(pll_35xx, fout_mpll, "fout_mpll", "fin_pll", MPLL_LOCK,
+ MPLL_CON0, "fout_mpll", NULL),
+ [bpll] = PLL(pll_35xx, fout_bpll, "fout_bpll", "fin_pll", BPLL_LOCK,
+ BPLL_CON0, NULL),
+ [gpll] = PLL(pll_35xx, fout_gpll, "fout_gpll", "fin_pll", GPLL_LOCK,
+ GPLL_CON0, NULL),
+ [cpll] = PLL(pll_35xx, fout_cpll, "fout_cpll", "fin_pll", CPLL_LOCK,
+ CPLL_CON0, NULL),
+ [epll] = PLL(pll_36xx, fout_epll, "fout_epll", "fin_pll", EPLL_LOCK,
+ EPLL_CON0, NULL),
+ [vpll] = PLL(pll_36xx, fout_vpll, "fout_vpll", "mout_vpllsrc",
+ VPLL_LOCK, VPLL_CON0, NULL),
};
static __initdata struct of_device_id ext_clk_match[] = {
@@ -474,7 +551,8 @@ static __initdata struct of_device_id ext_clk_match[] = {
void __init exynos5250_clk_init(struct device_node *np)
{
void __iomem *reg_base;
- struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll;
+ struct clk *vpllsrc;
+ unsigned long fin_pll_rate, mout_vpllsrc_rate = 0;
if (np) {
reg_base = of_iomap(np, 0);
@@ -490,22 +568,23 @@ void __init exynos5250_clk_init(struct device_node *np)
samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
ext_clk_match);
+ samsung_clk_register_mux(exynos5250_pll_pmux_clks,
+ ARRAY_SIZE(exynos5250_pll_pmux_clks));
+
+ fin_pll_rate = _get_rate("fin_pll");
+
+ if (fin_pll_rate == 24 * MHZ)
+ exynos5250_plls[epll].rate_table = epll_24mhz_tbl;
+
+ vpllsrc = __clk_lookup("mout_vpllsrc");
+ if (vpllsrc)
+ mout_vpllsrc_rate = clk_get_rate(vpllsrc);
- apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
- reg_base + 0x100);
- mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
- reg_base + 0x4100);
- bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll",
- reg_base + 0x20110);
- gpll = samsung_clk_register_pll35xx("fout_gpll", "fin_pll",
- reg_base + 0x10150);
- cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll",
- reg_base + 0x10120);
- epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
- reg_base + 0x10130);
- vpll = samsung_clk_register_pll36xx("fout_vpll", "mout_vpllsrc",
- reg_base + 0x10140);
+ if (mout_vpllsrc_rate == 24 * MHZ)
+ exynos5250_plls[vpll].rate_table = vpll_24mhz_tbl;
+ samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls),
+ reg_base);
samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks,
ARRAY_SIZE(exynos5250_fixed_rate_clks));
samsung_clk_register_fixed_factor(exynos5250_fixed_factor_clks,
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 68a96cbd4936..86dfc6440438 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -17,13 +17,30 @@
#include <linux/of_address.h>
#include "clk.h"
-#include "clk-pll.h"
+#define APLL_LOCK 0x0
+#define APLL_CON0 0x100
#define SRC_CPU 0x200
#define DIV_CPU0 0x500
#define DIV_CPU1 0x504
#define GATE_BUS_CPU 0x700
#define GATE_SCLK_CPU 0x800
+#define CPLL_LOCK 0x10020
+#define DPLL_LOCK 0x10030
+#define EPLL_LOCK 0x10040
+#define RPLL_LOCK 0x10050
+#define IPLL_LOCK 0x10060
+#define SPLL_LOCK 0x10070
+#define VPLL_LOCK 0x10070
+#define MPLL_LOCK 0x10090
+#define CPLL_CON0 0x10120
+#define DPLL_CON0 0x10128
+#define EPLL_CON0 0x10130
+#define RPLL_CON0 0x10140
+#define IPLL_CON0 0x10150
+#define SPLL_CON0 0x10160
+#define VPLL_CON0 0x10170
+#define MPLL_CON0 0x10180
#define SRC_TOP0 0x10200
#define SRC_TOP1 0x10204
#define SRC_TOP2 0x10208
@@ -75,15 +92,27 @@
#define GATE_TOP_SCLK_MAU 0x1083c
#define GATE_TOP_SCLK_FSYS 0x10840
#define GATE_TOP_SCLK_PERIC 0x10850
+#define BPLL_LOCK 0x20010
+#define BPLL_CON0 0x20110
#define SRC_CDREX 0x20200
+#define KPLL_LOCK 0x28000
+#define KPLL_CON0 0x28100
#define SRC_KFC 0x28200
#define DIV_KFC0 0x28500
+/* list of PLLs */
+enum exynos5420_plls {
+ apll, cpll, dpll, epll, rpll, ipll, spll, vpll, mpll,
+ bpll, kpll,
+ nr_plls /* number of PLLs */
+};
+
enum exynos5420_clks {
none,
/* core clocks */
- fin_pll,
+ fin_pll, fout_apll, fout_cpll, fout_dpll, fout_epll, fout_rpll,
+ fout_ipll, fout_spll, fout_vpll, fout_mpll, fout_bpll, fout_kpll,
/* gate for special clocks (sclk) */
sclk_uart0 = 128, sclk_uart1, sclk_uart2, sclk_uart3, sclk_mmc0,
@@ -698,6 +727,31 @@ struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
GATE(smmu_mscl2, "smmu_mscl2", "aclk400_mscl", GATE_IP_MSCL, 10, 0, 0),
};
+struct __initdata samsung_pll_clock exynos5420_plls[nr_plls] = {
+ [apll] = PLL(pll_2550, fout_apll, "fout_apll", "fin_pll", APLL_LOCK,
+ APLL_CON0, NULL),
+ [cpll] = PLL(pll_2550, fout_mpll, "fout_mpll", "fin_pll", MPLL_LOCK,
+ MPLL_CON0, NULL),
+ [dpll] = PLL(pll_2550, fout_dpll, "fout_dpll", "fin_pll", DPLL_LOCK,
+ DPLL_CON0, NULL),
+ [epll] = PLL(pll_2650, fout_epll, "fout_epll", "fin_pll", EPLL_LOCK,
+ EPLL_CON0, NULL),
+ [rpll] = PLL(pll_2650, fout_rpll, "fout_rpll", "fin_pll", RPLL_LOCK,
+ RPLL_CON0, NULL),
+ [ipll] = PLL(pll_2550, fout_ipll, "fout_ipll", "fin_pll", IPLL_LOCK,
+ IPLL_CON0, NULL),
+ [spll] = PLL(pll_2550, fout_spll, "fout_spll", "fin_pll", SPLL_LOCK,
+ SPLL_CON0, NULL),
+ [vpll] = PLL(pll_2550, fout_vpll, "fout_vpll", "fin_pll", VPLL_LOCK,
+ VPLL_CON0, NULL),
+ [mpll] = PLL(pll_2550, fout_mpll, "fout_mpll", "fin_pll", MPLL_LOCK,
+ MPLL_CON0, NULL),
+ [bpll] = PLL(pll_2550, fout_bpll, "fout_bpll", "fin_pll", BPLL_LOCK,
+ BPLL_CON0, NULL),
+ [kpll] = PLL(pll_2550, fout_kpll, "fout_kpll", "fin_pll", KPLL_LOCK,
+ KPLL_CON0, NULL),
+};
+
static __initdata struct of_device_id ext_clk_match[] = {
{ .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, },
{ },
@@ -707,8 +761,6 @@ static __initdata struct of_device_id ext_clk_match[] = {
void __init exynos5420_clk_init(struct device_node *np)
{
void __iomem *reg_base;
- struct clk *apll, *bpll, *cpll, *dpll, *epll, *ipll, *kpll, *mpll;
- struct clk *rpll, *spll, *vpll;
if (np) {
reg_base = of_iomap(np, 0);
@@ -724,30 +776,8 @@ void __init exynos5420_clk_init(struct device_node *np)
samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5420_fixed_rate_ext_clks),
ext_clk_match);
-
- apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
- reg_base + 0x100);
- bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll",
- reg_base + 0x20110);
- cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll",
- reg_base + 0x10120);
- dpll = samsung_clk_register_pll35xx("fout_dpll", "fin_pll",
- reg_base + 0x10128);
- epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
- reg_base + 0x10130);
- ipll = samsung_clk_register_pll35xx("fout_ipll", "fin_pll",
- reg_base + 0x10150);
- kpll = samsung_clk_register_pll35xx("fout_kpll", "fin_pll",
- reg_base + 0x28100);
- mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
- reg_base + 0x10180);
- rpll = samsung_clk_register_pll36xx("fout_rpll", "fin_pll",
- reg_base + 0x10140);
- spll = samsung_clk_register_pll35xx("fout_spll", "fin_pll",
- reg_base + 0x10160);
- vpll = samsung_clk_register_pll35xx("fout_vpll", "fin_pll",
- reg_base + 0x10170);
-
+ samsung_clk_register_pll(exynos5420_plls, ARRAY_SIZE(exynos5420_plls),
+ reg_base);
samsung_clk_register_fixed_rate(exynos5420_fixed_rate_clks,
ARRAY_SIZE(exynos5420_fixed_rate_clks));
samsung_clk_register_fixed_factor(exynos5420_fixed_factor_clks,
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 362f12dcd944..f80efb6bc0b3 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -13,28 +13,67 @@
#include "clk.h"
#include "clk-pll.h"
+struct samsung_clk_pll {
+ struct clk_hw hw;
+ void __iomem *lock_reg;
+ void __iomem *con_reg;
+ enum samsung_pll_type type;
+ unsigned int rate_count;
+ const struct samsung_pll_rate_table *rate_table;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
+
+static const struct samsung_pll_rate_table *samsung_get_pll_settings(
+ struct samsung_clk_pll *pll, unsigned long rate)
+{
+ const struct samsung_pll_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate == rate_table[i].rate)
+ return &rate_table[i];
+ }
+
+ return NULL;
+}
+
+static long samsung_pll_round_rate(struct clk_hw *hw,
+ unsigned long drate, unsigned long *prate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ const struct samsung_pll_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ /* Assumming rate_table is in descending order */
+ for (i = 0; i < pll->rate_count; i++) {
+ if (drate >= rate_table[i].rate)
+ return rate_table[i].rate;
+ }
+
+ /* return minimum supported value */
+ return rate_table[i - 1].rate;
+}
+
/*
* PLL35xx Clock Type
*/
+/* Maximum lock time can be 270 * PDIV cycles */
+#define PLL35XX_LOCK_FACTOR (270)
#define PLL35XX_MDIV_MASK (0x3FF)
#define PLL35XX_PDIV_MASK (0x3F)
#define PLL35XX_SDIV_MASK (0x7)
+#define PLL35XX_LOCK_STAT_MASK (0x1)
#define PLL35XX_MDIV_SHIFT (16)
#define PLL35XX_PDIV_SHIFT (8)
#define PLL35XX_SDIV_SHIFT (0)
-
-struct samsung_clk_pll35xx {
- struct clk_hw hw;
- const void __iomem *con_reg;
-};
-
-#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw)
+#define PLL35XX_LOCK_STAT_SHIFT (29)
static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
- struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw);
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
u32 mdiv, pdiv, sdiv, pll_con;
u64 fvco = parent_rate;
@@ -49,48 +88,80 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
return (unsigned long)fvco;
}
-static const struct clk_ops samsung_pll35xx_clk_ops = {
- .recalc_rate = samsung_pll35xx_recalc_rate,
-};
-
-struct clk * __init samsung_clk_register_pll35xx(const char *name,
- const char *pname, const void __iomem *con_reg)
+static inline bool samsung_pll35xx_mp_change(
+ const struct samsung_pll_rate_table *rate, u32 pll_con)
{
- struct samsung_clk_pll35xx *pll;
- struct clk *clk;
- struct clk_init_data init;
+ u32 old_mdiv, old_pdiv;
- pll = kzalloc(sizeof(*pll), GFP_KERNEL);
- if (!pll) {
- pr_err("%s: could not allocate pll clk %s\n", __func__, name);
- return NULL;
+ old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
+ old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
+
+ return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
+}
+
+static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ const struct samsung_pll_rate_table *rate;
+ u32 tmp;
+
+ /* Get required rate settings from table */
+ rate = samsung_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
}
- init.name = name;
- init.ops = &samsung_pll35xx_clk_ops;
- init.flags = CLK_GET_RATE_NOCACHE;
- init.parent_names = &pname;
- init.num_parents = 1;
+ tmp = __raw_readl(pll->con_reg);
- pll->hw.init = &init;
- pll->con_reg = con_reg;
+ if (!(samsung_pll35xx_mp_change(rate, tmp))) {
+ /* If only s change, change just s value only*/
+ tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
+ tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
+ __raw_writel(tmp, pll->con_reg);
- clk = clk_register(NULL, &pll->hw);
- if (IS_ERR(clk)) {
- pr_err("%s: failed to register pll clock %s\n", __func__,
- name);
- kfree(pll);
+ return 0;
}
- if (clk_register_clkdev(clk, name, NULL))
- pr_err("%s: failed to register lookup for %s", __func__, name);
-
- return clk;
+ /* Set PLL lock time. */
+ __raw_writel(rate->pdiv * PLL35XX_LOCK_FACTOR,
+ pll->lock_reg);
+
+ /* Change PLL PMS values */
+ tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
+ (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
+ (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
+ tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
+ (rate->pdiv << PLL35XX_PDIV_SHIFT) |
+ (rate->sdiv << PLL35XX_SDIV_SHIFT);
+ __raw_writel(tmp, pll->con_reg);
+
+ /* wait_lock_time */
+ do {
+ cpu_relax();
+ tmp = __raw_readl(pll->con_reg);
+ } while (!(tmp & (PLL35XX_LOCK_STAT_MASK
+ << PLL35XX_LOCK_STAT_SHIFT)));
+ return 0;
}
+static const struct clk_ops samsung_pll35xx_clk_ops = {
+ .recalc_rate = samsung_pll35xx_recalc_rate,
+ .round_rate = samsung_pll_round_rate,
+ .set_rate = samsung_pll35xx_set_rate,
+};
+
+static const struct clk_ops samsung_pll35xx_clk_min_ops = {
+ .recalc_rate = samsung_pll35xx_recalc_rate,
+};
+
/*
* PLL36xx Clock Type
*/
+/* Maximum lock time can be 3000 * PDIV cycles */
+#define PLL36XX_LOCK_FACTOR (3000)
#define PLL36XX_KDIV_MASK (0xFFFF)
#define PLL36XX_MDIV_MASK (0x1FF)
@@ -99,18 +170,13 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name,
#define PLL36XX_MDIV_SHIFT (16)
#define PLL36XX_PDIV_SHIFT (8)
#define PLL36XX_SDIV_SHIFT (0)
-
-struct samsung_clk_pll36xx {
- struct clk_hw hw;
- const void __iomem *con_reg;
-};
-
-#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw)
+#define PLL36XX_KDIV_SHIFT (0)
+#define PLL36XX_LOCK_STAT_SHIFT (29)
static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
- struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw);
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
s16 kdiv;
u64 fvco = parent_rate;
@@ -129,45 +195,80 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
return (unsigned long)fvco;
}
-static const struct clk_ops samsung_pll36xx_clk_ops = {
- .recalc_rate = samsung_pll36xx_recalc_rate,
-};
-
-struct clk * __init samsung_clk_register_pll36xx(const char *name,
- const char *pname, const void __iomem *con_reg)
+static inline bool samsung_pll36xx_mpk_change(
+ const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
{
- struct samsung_clk_pll36xx *pll;
- struct clk *clk;
- struct clk_init_data init;
+ u32 old_mdiv, old_pdiv, old_kdiv;
- pll = kzalloc(sizeof(*pll), GFP_KERNEL);
- if (!pll) {
- pr_err("%s: could not allocate pll clk %s\n", __func__, name);
- return NULL;
+ old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
+ old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
+ old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
+
+ return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
+ rate->kdiv != old_kdiv);
+}
+
+static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 tmp, pll_con0, pll_con1;
+ const struct samsung_pll_rate_table *rate;
+
+ rate = samsung_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
}
- init.name = name;
- init.ops = &samsung_pll36xx_clk_ops;
- init.flags = CLK_GET_RATE_NOCACHE;
- init.parent_names = &pname;
- init.num_parents = 1;
+ pll_con0 = __raw_readl(pll->con_reg);
+ pll_con1 = __raw_readl(pll->con_reg + 4);
- pll->hw.init = &init;
- pll->con_reg = con_reg;
+ if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
+ /* If only s change, change just s value only*/
+ pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
+ pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
+ __raw_writel(pll_con0, pll->con_reg);
- clk = clk_register(NULL, &pll->hw);
- if (IS_ERR(clk)) {
- pr_err("%s: failed to register pll clock %s\n", __func__,
- name);
- kfree(pll);
+ return 0;
}
- if (clk_register_clkdev(clk, name, NULL))
- pr_err("%s: failed to register lookup for %s", __func__, name);
-
- return clk;
+ /* Set PLL lock time. */
+ __raw_writel(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
+
+ /* Change PLL PMS values */
+ pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
+ (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
+ (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
+ pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
+ (rate->pdiv << PLL36XX_PDIV_SHIFT) |
+ (rate->sdiv << PLL36XX_SDIV_SHIFT);
+ __raw_writel(pll_con0, pll->con_reg);
+
+ pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
+ pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
+ __raw_writel(pll_con1, pll->con_reg + 4);
+
+ /* wait_lock_time */
+ do {
+ cpu_relax();
+ tmp = __raw_readl(pll->con_reg);
+ } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
+
+ return 0;
}
+static const struct clk_ops samsung_pll36xx_clk_ops = {
+ .recalc_rate = samsung_pll36xx_recalc_rate,
+ .set_rate = samsung_pll36xx_set_rate,
+ .round_rate = samsung_pll_round_rate,
+};
+
+static const struct clk_ops samsung_pll36xx_clk_min_ops = {
+ .recalc_rate = samsung_pll36xx_recalc_rate,
+};
+
/*
* PLL45xx Clock Type
*/
@@ -418,3 +519,93 @@ struct clk * __init samsung_clk_register_pll2550x(const char *name,
return clk;
}
+
+static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
+ void __iomem *base)
+{
+ struct samsung_clk_pll *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+ int ret, len;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll) {
+ pr_err("%s: could not allocate pll clk %s\n",
+ __func__, pll_clk->name);
+ return;
+ }
+
+ init.name = pll_clk->name;
+ init.flags = pll_clk->flags;
+ init.parent_names = &pll_clk->parent_name;
+ init.num_parents = 1;
+
+ if (pll_clk->rate_table) {
+ /* find count of rates in rate_table */
+ for (len = 0; pll_clk->rate_table[len].rate != 0; )
+ len++;
+
+ pll->rate_count = len;
+ pll->rate_table = kmemdup(pll_clk->rate_table,
+ pll->rate_count *
+ sizeof(struct samsung_pll_rate_table),
+ GFP_KERNEL);
+ WARN(!pll->rate_table,
+ "%s: could not allocate rate table for %s\n",
+ __func__, pll_clk->name);
+ }
+
+ switch (pll_clk->type) {
+ /* clk_ops for 35xx and 2550 are similar */
+ case pll_35xx:
+ case pll_2550:
+ if (!pll->rate_table)
+ init.ops = &samsung_pll35xx_clk_min_ops;
+ else
+ init.ops = &samsung_pll35xx_clk_ops;
+ break;
+ /* clk_ops for 36xx and 2650 are similar */
+ case pll_36xx:
+ case pll_2650:
+ if (!pll->rate_table)
+ init.ops = &samsung_pll36xx_clk_min_ops;
+ else
+ init.ops = &samsung_pll36xx_clk_ops;
+ break;
+ default:
+ pr_warn("%s: Unknown pll type for pll clk %s\n",
+ __func__, pll_clk->name);
+ }
+
+ pll->hw.init = &init;
+ pll->type = pll_clk->type;
+ pll->lock_reg = base + pll_clk->lock_offset;
+ pll->con_reg = base + pll_clk->con_offset;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll clock %s : %ld\n",
+ __func__, pll_clk->name, PTR_ERR(clk));
+ kfree(pll);
+ return;
+ }
+
+ samsung_clk_add_lookup(clk, pll_clk->id);
+
+ if (!pll_clk->alias)
+ return;
+
+ ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
+ if (ret)
+ pr_err("%s: failed to register lookup for %s : %d",
+ __func__, pll_clk->name, ret);
+}
+
+void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
+ unsigned int nr_pll, void __iomem *base)
+{
+ int cnt;
+
+ for (cnt = 0; cnt < nr_pll; cnt++)
+ _samsung_clk_register_pll(&pll_list[cnt], base);
+}
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index f33786e9a78b..95ae23d75b3c 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -12,6 +12,40 @@
#ifndef __SAMSUNG_CLK_PLL_H
#define __SAMSUNG_CLK_PLL_H
+enum samsung_pll_type {
+ pll_35xx,
+ pll_36xx,
+ pll_2550,
+ pll_2650,
+};
+
+#define PLL_35XX_RATE(_rate, _m, _p, _s) \
+ { \
+ .rate = (_rate), \
+ .mdiv = (_m), \
+ .pdiv = (_p), \
+ .sdiv = (_s), \
+ }
+
+#define PLL_36XX_RATE(_rate, _m, _p, _s, _k) \
+ { \
+ .rate = (_rate), \
+ .mdiv = (_m), \
+ .pdiv = (_p), \
+ .sdiv = (_s), \
+ .kdiv = (_k), \
+ }
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+
+struct samsung_pll_rate_table {
+ unsigned int rate;
+ unsigned int pdiv;
+ unsigned int mdiv;
+ unsigned int sdiv;
+ unsigned int kdiv;
+};
+
enum pll45xx_type {
pll_4500,
pll_4502,
@@ -24,10 +58,6 @@ enum pll46xx_type {
pll_4650c,
};
-extern struct clk * __init samsung_clk_register_pll35xx(const char *name,
- const char *pname, const void __iomem *con_reg);
-extern struct clk * __init samsung_clk_register_pll36xx(const char *name,
- const char *pname, const void __iomem *con_reg);
extern struct clk * __init samsung_clk_register_pll45xx(const char *name,
const char *pname, const void __iomem *con_reg,
enum pll45xx_type type);
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 2f7dba20ced8..e7dfccb5d981 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -19,6 +19,7 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include "clk-pll.h"
/**
* struct samsung_clock_alias: information about mux clock
@@ -39,6 +40,8 @@ struct samsung_clock_alias {
.alias = a, \
}
+#define MHZ (1000 * 1000)
+
/**
* struct samsung_fixed_rate_clock: information about fixed-rate clock
* @id: platform specific id of the clock.
@@ -261,6 +264,54 @@ struct samsung_clk_reg_dump {
u32 value;
};
+/**
+ * struct samsung_pll_clock: information about pll clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this pll clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @con_offset: offset of the register for configuring the PLL.
+ * @lock_offset: offset of the register for locking the PLL.
+ * @type: Type of PLL to be registered.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_pll_clock {
+ unsigned int id;
+ const char *dev_name;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ int con_offset;
+ int lock_offset;
+ enum samsung_pll_type type;
+ const struct samsung_pll_rate_table *rate_table;
+ const char *alias;
+};
+
+#define __PLL(_typ, _id, _dname, _name, _pname, _flags, _lock, _con, \
+ _rtable, _alias) \
+ { \
+ .id = _id, \
+ .type = _typ, \
+ .dev_name = _dname, \
+ .name = _name, \
+ .parent_name = _pname, \
+ .flags = CLK_GET_RATE_NOCACHE, \
+ .con_offset = _con, \
+ .lock_offset = _lock, \
+ .rate_table = _rtable, \
+ .alias = _alias, \
+ }
+
+#define PLL(_typ, _id, _name, _pname, _lock, _con, _rtable) \
+ __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \
+ _lock, _con, _rtable, _name)
+
+#define PLL_A(_typ, _id, _name, _pname, _lock, _con, _alias, _rtable) \
+ __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \
+ _lock, _con, _rtable, _alias)
+
extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
unsigned long nr_clks, unsigned long *rdump,
unsigned long nr_rdump, unsigned long *soc_rdump,
@@ -284,6 +335,8 @@ extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
unsigned int nr_clk);
extern void __init samsung_clk_register_gate(
struct samsung_gate_clock *clk_list, unsigned int nr_clk);
+extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
+ unsigned int nr_clk, void __iomem *base);
extern unsigned long _get_rate(const char *clk_name);
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index b2bbc415f120..23d318267da8 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -27,6 +27,8 @@
#include <asm/localtimer.h>
#include <asm/mach/time.h>
+#include <plat/cpu.h>
+
#define EXYNOS4_MCTREG(x) (x)
#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)
#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)
@@ -194,6 +196,10 @@ static void __init exynos4_clocksource_init(void)
{
exynos4_mct_frc_start(0, 0);
+ if (soc_is_exynos5250()) {
+ mct_frc.rating = 399;
+ }
+
if (clocksource_register_hz(&mct_frc, clk_rate))
panic("%s: can't register clocksource\n", mct_frc.name);
}
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 0d32f02ef4d6..630b503736e0 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -17,6 +17,8 @@
#include <linux/regulator/consumer.h>
#include <linux/cpufreq.h>
#include <linux/suspend.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
#include <plat/cpu.h>
@@ -245,8 +247,35 @@ static struct notifier_block exynos_cpufreq_nb = {
.notifier_call = exynos_cpufreq_pm_notifier,
};
+static int exynos_cpufreq_reboot_notifier(struct notifier_block *this,
+ unsigned long code, void *_cmd)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
+ mutex_lock(&cpufreq_lock);
+
+ if (frequency_locked)
+ goto out;
+ frequency_locked = true;
+
+ if (locking_frequency) {
+ mutex_unlock(&cpufreq_lock);
+ exynos_target(policy, locking_frequency, CPUFREQ_RELATION_H);
+ mutex_lock(&cpufreq_lock);
+ }
+
+out:
+ mutex_unlock(&cpufreq_lock);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block exynos_cpufreq_reboot_nb = {
+ .notifier_call = exynos_cpufreq_reboot_notifier,
+};
+
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
+ int ret;
+
policy->cur = policy->min = policy->max = exynos_getspeed(policy->cpu);
cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
@@ -256,7 +285,13 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpumask_setall(policy->cpus);
- return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
+ ret = cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
+ if (ret)
+ return ret;
+
+ cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
+ return 0;
+
}
static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
@@ -319,6 +354,7 @@ static int __init exynos_cpufreq_init(void)
locking_frequency = exynos_getspeed(0);
register_pm_notifier(&exynos_cpufreq_nb);
+ register_reboot_notifier(&exynos_cpufreq_reboot_nb);
if (cpufreq_register_driver(&exynos_driver)) {
pr_err("%s: failed to register cpufreq driver\n", __func__);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index ca2729a85129..812178df0ee2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -287,7 +287,8 @@ static struct drm_driver exynos_drm_driver = {
static int exynos_drm_platform_probe(struct platform_device *pdev)
{
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
return drm_platform_init(&exynos_drm_driver, pdev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 1c263dac3c1c..a0346ae3b59c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of_device.h>
+#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <video/of_display_timing.h>
@@ -101,9 +102,12 @@ struct fimd_context {
struct exynos_drm_subdrv subdrv;
int irq;
struct drm_crtc *crtc;
+ struct clk *sclk_mout_fimd;
+ struct clk *fimd_mux_clk;
struct clk *bus_clk;
struct clk *lcd_clk;
void __iomem *regs;
+ void __iomem *sys_reg;
struct fimd_win_data win_data[WINDOWS_NR];
unsigned int clkdiv;
unsigned int default_win;
@@ -784,6 +788,7 @@ static int fimd_calc_clkdiv(struct fimd_context *ctx,
}
}
+ clkdiv = 5;
return clkdiv;
}
@@ -859,6 +864,7 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
if (ret < 0)
return ret;
+ writel((3 << 0), ctx->regs + 0x27c);
ctx->suspended = false;
/* if vblank was enabled status, enable it again. */
@@ -884,6 +890,7 @@ static int fimd_probe(struct platform_device *pdev)
struct exynos_drm_fimd_pdata *pdata;
struct exynos_drm_panel_info *panel;
struct resource *res;
+ struct device_node *sys_reg_node;
int win;
int ret = -EINVAL;
@@ -930,6 +937,24 @@ static int fimd_probe(struct platform_device *pdev)
return PTR_ERR(ctx->lcd_clk);
}
+ /* Set the parent for FIMD pixel clock */
+ ctx->fimd_mux_clk = devm_clk_get(dev, "mout_fimd");
+ if (IS_ERR(ctx->fimd_mux_clk)) {
+ dev_err(dev, "failed to get fimd mux clk\n");
+ return PTR_ERR(ctx->fimd_mux_clk);
+ }
+
+ ctx->sclk_mout_fimd = devm_clk_get(dev, "sclk_mout_fimd");
+ if (IS_ERR(ctx->sclk_mout_fimd)) {
+ dev_err(dev, "failed to get mout_fimd parent\n");
+ return PTR_ERR(ctx->sclk_mout_fimd);
+ }
+
+ clk_set_parent(ctx->fimd_mux_clk, ctx->sclk_mout_fimd);
+
+ /* Set the FIMD pixel clock to desired value */
+ clk_set_rate(ctx->lcd_clk, (1000 * PICOS2KHZ(panel->timing.pixclock)));
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctx->regs = devm_ioremap_resource(dev, res);
@@ -984,6 +1009,19 @@ static int fimd_probe(struct platform_device *pdev)
exynos_drm_subdrv_register(subdrv);
+ sys_reg_node = of_parse_phandle(dev->of_node, "samsung,sys-reg", 0);
+
+ if(!sys_reg_node)
+ return -EINVAL;
+
+ ctx->sys_reg = of_iomap(sys_reg_node, 0);
+ if (!ctx->sys_reg)
+ return -EINVAL;
+
+ writel(((1 << 15) | readl(ctx->sys_reg + 0x214)), ctx->sys_reg + 0x214);
+
+ writel((3 << 0), ctx->regs + 0x27c);
+
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 2f5c6942c968..44361abe2320 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -33,6 +33,7 @@
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
+#include <linux/of_address.h>
#include <drm/exynos_drm.h>
@@ -81,7 +82,6 @@ struct hdmi_resources {
struct clk *sclk_hdmi;
struct clk *sclk_pixel;
struct clk *sclk_hdmiphy;
- struct clk *hdmiphy;
struct clk *mout_hdmi;
struct regulator_bulk_data *regul_bulk;
int regul_count;
@@ -188,6 +188,7 @@ struct hdmi_context {
struct mutex hdmi_mutex;
void __iomem *regs;
+ void __iomem *phy_pow_ctrl_reg;
void *parent_ctx;
int irq;
@@ -403,6 +404,14 @@ static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
writel(value, hdata->regs + reg_id);
}
+static inline void hdmi_phy_pow_ctrl_reg_writemask(struct hdmi_context *hdata,
+ u32 value, u32 mask)
+{
+ u32 old = readl(hdata->phy_pow_ctrl_reg);
+ value = (value & mask) | (old & ~mask);
+ writel(value, hdata->phy_pow_ctrl_reg);
+}
+
static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
{
#define DUMPREG(reg_id) \
@@ -1685,7 +1694,8 @@ static void hdmi_poweron(struct hdmi_context *hdata)
if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
DRM_DEBUG_KMS("failed to enable regulator bulk\n");
- clk_prepare_enable(res->hdmiphy);
+ hdmi_phy_pow_ctrl_reg_writemask(hdata, PMU_HDMI_PHY_ENABLE,
+ PMU_HDMI_PHY_CONTROL_MASK);
clk_prepare_enable(res->hdmi);
clk_prepare_enable(res->sclk_hdmi);
@@ -1710,7 +1720,8 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
clk_disable_unprepare(res->sclk_hdmi);
clk_disable_unprepare(res->hdmi);
- clk_disable_unprepare(res->hdmiphy);
+ hdmi_phy_pow_ctrl_reg_writemask(hdata, PMU_HDMI_PHY_DISABLE,
+ PMU_HDMI_PHY_CONTROL_MASK);
regulator_bulk_disable(res->regul_count, res->regul_bulk);
mutex_lock(&hdata->hdmi_mutex);
@@ -1763,7 +1774,7 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
struct hdmi_context *hdata = ctx->ctx;
mutex_lock(&hdata->hdmi_mutex);
- hdata->hpd = gpio_get_value(hdata->hpd_gpio);
+ hdata->hpd = true; /* gpio_get_value(hdata->hpd_gpio); */
mutex_unlock(&hdata->hdmi_mutex);
if (ctx->drm_dev)
@@ -1809,11 +1820,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
goto fail;
}
- res->hdmiphy = devm_clk_get(dev, "hdmiphy");
- if (IS_ERR(res->hdmiphy)) {
- DRM_ERROR("failed to get clock 'hdmiphy'\n");
- goto fail;
- }
res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
if (IS_ERR(res->mout_hdmi)) {
DRM_ERROR("failed to get clock 'mout_hdmi'\n");
@@ -1839,6 +1845,13 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
}
res->regul_count = ARRAY_SIZE(supply);
+ clk_prepare(res->hdmi);
+ clk_prepare(res->sclk_hdmi);
+ clk_prepare(res->sclk_pixel);
+ clk_prepare(res->sclk_hdmiphy);
+
+ clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+
return 0;
fail:
DRM_ERROR("HDMI resource init - failed\n");
@@ -1885,12 +1898,52 @@ static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
err_data:
return NULL;
}
+
+static int drm_hdmi_dt_parse_phy_pow_control(struct hdmi_context *hdata)
+{
+ struct device_node *phy_pow_ctrl_node;
+ u32 buf[2];
+ int ret = 0;
+
+ phy_pow_ctrl_node = of_find_node_by_name(NULL, "phy-power-control");
+ if (!phy_pow_ctrl_node) {
+ DRM_ERROR("Failed to find phy power control node\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ /* reg property holds two informations: addr of pmu register, size */
+ if (of_property_read_u32_array(phy_pow_ctrl_node, "reg",
+ (u32 *)&buf, 2)) {
+ DRM_ERROR("faild to get phy power control reg\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ hdata->phy_pow_ctrl_reg = devm_ioremap(hdata->dev, buf[0], buf[1]);
+ if (!hdata->phy_pow_ctrl_reg) {
+ DRM_ERROR("failed to ioremap phy pmu reg\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+fail:
+ of_node_put(phy_pow_ctrl_node);
+ return ret;
+}
+
#else
static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
(struct device *dev)
{
return NULL;
}
+
+static int drm_hdmi_dt_parse_phy_pow_control(struct hdmi_context *hdata)
+{
+ return 0;
+}
+
#endif
static struct platform_device_id hdmi_driver_types[] = {
@@ -1993,20 +2046,30 @@ static int hdmi_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdata->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(hdata->regs))
- return PTR_ERR(hdata->regs);
+ hdata->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hdata->regs)) {
+ ret = PTR_ERR(hdata->regs);
+ goto err_clk_res;
+ }
ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
if (ret) {
DRM_ERROR("failed to request HPD gpio\n");
+ goto err_clk_res;
+ }
+
+ /* map hdmiphy power control reg */
+ ret = drm_hdmi_dt_parse_phy_pow_control(hdata);
+ if (ret) {
+ DRM_ERROR("failed to map phy power control registers\n");
return ret;
}
/* DDC i2c driver */
if (i2c_add_driver(&ddc_driver)) {
DRM_ERROR("failed to register ddc i2c driver\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto err_clk_res;
}
hdata->ddc_port = hdmi_ddc;
@@ -2027,7 +2090,7 @@ static int hdmi_probe(struct platform_device *pdev)
goto err_hdmiphy;
}
- hdata->hpd = gpio_get_value(hdata->hpd_gpio);
+ hdata->hpd = true; /* gpio_get_value(hdata->hpd_gpio); */
ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
hdmi_irq_thread, IRQF_TRIGGER_RISING |
@@ -2052,12 +2115,19 @@ err_hdmiphy:
i2c_del_driver(&hdmiphy_driver);
err_ddc:
i2c_del_driver(&ddc_driver);
+err_clk_res:
+ clk_unprepare(hdata->res.hdmi);
+ clk_unprepare(hdata->res.sclk_hdmi);
+ clk_unprepare(hdata->res.sclk_pixel);
+ clk_unprepare(hdata->res.sclk_hdmiphy);
return ret;
}
static int hdmi_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
+ struct hdmi_context *hdata = ctx->ctx;
pm_runtime_disable(dev);
@@ -2066,9 +2136,22 @@ static int hdmi_remove(struct platform_device *pdev)
/* DDC i2c driver */
i2c_del_driver(&ddc_driver);
+ clk_unprepare(hdata->res.hdmi);
+ clk_unprepare(hdata->res.sclk_hdmi);
+ clk_unprepare(hdata->res.sclk_pixel);
+ clk_unprepare(hdata->res.sclk_hdmiphy);
return 0;
}
+static void hdmi_shutdown(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
+ struct hdmi_context *hdata = ctx->ctx;
+
+ hdmi_poweroff(hdata);
+}
+
#ifdef CONFIG_PM_SLEEP
static int hdmi_suspend(struct device *dev)
{
@@ -2096,7 +2179,7 @@ static int hdmi_resume(struct device *dev)
struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
struct hdmi_context *hdata = ctx->ctx;
- hdata->hpd = gpio_get_value(hdata->hpd_gpio);
+ hdata->hpd = true; /* gpio_get_value(hdata->hpd_gpio); */
enable_irq(hdata->irq);
@@ -2141,6 +2224,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
struct platform_driver hdmi_driver = {
.probe = hdmi_probe,
.remove = hdmi_remove,
+ .shutdown = hdmi_shutdown,
.id_table = hdmi_driver_types,
.driver = {
.name = "exynos-hdmi",
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index c9a137caea41..b6d7bc54f1fa 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -1085,6 +1085,9 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
}
mixer_res->irq = res->start;
+ clk_prepare(mixer_res->mixer);
+ clk_prepare(mixer_res->sclk_hdmi);
+
return 0;
}
@@ -1112,9 +1115,6 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
return -ENODEV;
}
- if (mixer_res->sclk_hdmi)
- clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res == NULL) {
dev_err(dev, "get memory resource failed.\n");
@@ -1128,6 +1128,13 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
return -ENXIO;
}
+ clk_prepare(mixer_res->vp);
+ clk_prepare(mixer_res->sclk_mixer);
+ clk_prepare(mixer_res->sclk_dac);
+
+ if (mixer_res->sclk_hdmi)
+ clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
+
return 0;
}
@@ -1229,7 +1236,7 @@ static int mixer_probe(struct platform_device *pdev)
ret = vp_resources_init(drm_hdmi_ctx, pdev);
if (ret) {
DRM_ERROR("vp_resources_init failed\n");
- goto fail;
+ goto out_vp;
}
}
@@ -1243,7 +1250,9 @@ static int mixer_probe(struct platform_device *pdev)
return 0;
-
+out_vp:
+ clk_unprepare(ctx->mixer_res.sclk_hdmi);
+ clk_unprepare(ctx->mixer_res.mixer);
fail:
dev_info(dev, "probe failed\n");
return ret;
@@ -1251,10 +1260,23 @@ fail:
static int mixer_remove(struct platform_device *pdev)
{
+ struct exynos_drm_hdmi_context *drm_hdmi_ctx =
+ get_mixer_context(&pdev->dev);
+ struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+
dev_info(&pdev->dev, "remove successful\n");
pm_runtime_disable(&pdev->dev);
+ clk_unprepare(ctx->mixer_res.mixer);
+ clk_unprepare(ctx->mixer_res.sclk_hdmi);
+
+ if (ctx->vp_enabled) {
+ clk_unprepare(ctx->mixer_res.vp);
+ clk_unprepare(ctx->mixer_res.sclk_mixer);
+ clk_unprepare(ctx->mixer_res.sclk_dac);
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index ef1b3eb3ba6e..8d9ca2543ed8 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -578,4 +578,8 @@
#define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074)
#define HDMI_TG_3D HDMI_TG_BASE(0x00F0)
+#define PMU_HDMI_PHY_CONTROL_MASK (1 << 0)
+#define PMU_HDMI_PHY_ENABLE (1)
+#define PMU_HDMI_PHY_DISABLE (0)
+
#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index cab1c91b75a3..4b166bce60c2 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -86,6 +86,7 @@
#define QUIRK_S3C2440 (1 << 0)
#define QUIRK_HDMIPHY (1 << 1)
#define QUIRK_NO_GPIO (1 << 2)
+#define QUIRK_POLL (1 << 3)
/* Max time to wait for bus to become idle after a xfer (in us) */
#define S3C2410_IDLE_TIMEOUT 5000
@@ -142,6 +143,8 @@ static struct platform_device_id s3c24xx_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat);
+
#ifdef CONFIG_OF
static const struct of_device_id s3c24xx_i2c_match[] = {
{ .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
@@ -150,6 +153,8 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
.data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
{ .compatible = "samsung,exynos5440-i2c",
.data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) },
+ { .compatible = "samsung,exynos5-sata-phy-i2c",
+ .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) },
{},
};
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
@@ -188,7 +193,8 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
if (ret)
i2c->msg_idx = ret;
- wake_up(&i2c->wait);
+ if (!(i2c->quirks & QUIRK_POLL))
+ wake_up(&i2c->wait);
}
static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
@@ -225,6 +231,22 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
}
+static bool is_ack(struct s3c24xx_i2c *i2c)
+{
+ u32 time_out = i2c->tx_setup;
+
+ while (--time_out) {
+ if (readl(i2c->regs + S3C2410_IICCON)
+ & S3C2410_IICCON_IRQPEND) {
+ if (!(readl(i2c->regs + S3C2410_IICSTAT)
+ & S3C2410_IICSTAT_LASTBIT))
+ return true;
+ }
+ udelay(time_out);
+ }
+
+ return false;
+}
/* s3c24xx_i2c_message_start
*
@@ -269,6 +291,16 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
stat |= S3C2410_IICSTAT_START;
writel(stat, i2c->regs + S3C2410_IICSTAT);
+
+ if (i2c->quirks & QUIRK_POLL) {
+ while ((i2c->msg_num != 0) && is_ack(i2c)) {
+ i2c_s3c_irq_nextbyte(i2c, stat);
+ stat = readl(i2c->regs + S3C2410_IICSTAT);
+
+ if (stat & S3C2410_IICSTAT_ARBITR)
+ dev_err(i2c->dev, "deal with arbitration loss\n");
+ }
+ }
}
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
@@ -676,6 +708,15 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
s3c24xx_i2c_enable_irq(i2c);
s3c24xx_i2c_message_start(i2c, msgs);
+ if (i2c->quirks & QUIRK_POLL) {
+ ret = i2c->msg_idx;
+
+ if (ret != num)
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+ goto out;
+ }
+
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
ret = i2c->msg_idx;
@@ -821,6 +862,9 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
if (div1 == 512)
iiccon |= S3C2410_IICCON_TXDIV_512;
+ if (i2c->quirks & QUIRK_POLL)
+ iiccon |= S3C2410_IICCON_SCALE(2);
+
writel(iiccon, i2c->regs + S3C2410_IICCON);
if (i2c->quirks & QUIRK_S3C2440) {
@@ -1118,18 +1162,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
* ensure no current IRQs pending
*/
- i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find IRQ\n");
- return ret;
- }
+ if (!(i2c->quirks & QUIRK_POLL)) {
+ i2c->irq = ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ return ret;
+ }
- ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
- dev_name(&pdev->dev), i2c);
+ ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
+ dev_name(&pdev->dev), i2c);
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
- return ret;
+ if (ret != 0) {
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ return ret;
+ }
}
ret = s3c24xx_i2c_register_cpufreq(i2c);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 4f6dd42c9adb..da08a1701b66 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -197,6 +197,16 @@ static struct mfc_control controls[] = {
.default_value = 1,
.is_volatile = 1,
},
+ {
+ .id = V4L2_CID_CODEC_FRAME_TAG,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame Tag",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ .is_volatile = 1,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(controls)
@@ -718,6 +728,9 @@ static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
ctx->slice_interface = ctrl->val;
break;
+ case V4L2_CID_CODEC_FRAME_TAG:
+ ctx->frame_tag = ctrl->val;
+ break;
default:
mfc_err("Invalid control 0x%08x\n", ctrl->id);
return -EINVAL;
@@ -752,6 +765,9 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
break;
+ case V4L2_CID_CODEC_FRAME_TAG:
+ ctrl->val = s5p_mfc_hw_call(dev->mfc_ops, get_frame_tag, ctx);
+ break;
}
return 0;
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 754c540e7a7e..498ff09a8158 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -77,6 +77,7 @@ struct s5p_mfc_hw_ops {
unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx);
unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx);
unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx);
+ unsigned int (*get_frame_tag)(struct s5p_mfc_ctx *ctx);
};
void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 368582b091bf..c7408bcffa6f 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -1075,6 +1075,9 @@ static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+
+ s5p_mfc_write_info_v5(ctx, ctx->frame_tag,
+ S5P_FIMV_SHARED_SET_FRAME_TAG);
}
/* Decode a single frame */
@@ -1682,6 +1685,11 @@ static unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx)
return s5p_mfc_read_info_v5(ctx, CROP_INFO_V);
}
+unsigned int s5p_mfc_get_frame_tag(struct s5p_mfc_ctx *ctx)
+{
+ return s5p_mfc_read_info_v5(ctx, GET_FRAME_TAG_TOP);
+}
+
/* Initialize opr function pointers for MFC v5 */
static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
.alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5,
@@ -1735,6 +1743,7 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
.get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5,
.get_crop_info_h = s5p_mfc_get_crop_info_h_v5,
.get_crop_info_v = s5p_mfc_get_crop_info_v_v5,
+ .get_frame_tag = s5p_mfc_get_frame_tag,
};
struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index fccd08b66d1a..1294b215c42c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -699,6 +699,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count";
case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control";
case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header";
+ case V4L2_CID_CODEC_FRAME_TAG: return "Video Decoder Frame Tag";
/* CAMERA controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -973,6 +974,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
*min = *max = *step = *def = 0;
break;
+ case V4L2_CID_CODEC_FRAME_TAG:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *step = 1;
+ *min = 0;
+ *max = INT_MAX;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index ad5d1e4384db..defda0e64bde 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -44,6 +44,35 @@ struct ax88172_int_data {
__le16 res3;
} __packed;
+static char asix_mac_addr[6];
+static int __init asix_setup_mac(char *macstr)
+{
+ int i, h, l;
+
+ if (!macstr)
+ return 0;
+
+ for (i = 0; i < 6; i++) {
+ if (i != 5 && *(macstr + 2) != ':')
+ return 0;
+
+ h = hex_to_bin(*macstr++);
+ if (h == -1)
+ return 0;
+
+ l = hex_to_bin(*macstr++);
+ if (l == -1)
+ return 0;
+
+ macstr++;
+ asix_mac_addr[i] = (h << 4) + l;
+ }
+
+ return 0;
+}
+
+__setup("mac=", asix_setup_mac);
+
static void asix_status(struct usbnet *dev, struct urb *urb)
{
struct ax88172_int_data *event;
@@ -62,6 +91,9 @@ static void asix_status(struct usbnet *dev, struct urb *urb)
static void asix_set_netdev_dev_addr(struct usbnet *dev, u8 *addr)
{
+ if (!is_valid_ether_addr(addr))
+ memcpy(addr, asix_mac_addr, ETH_ALEN);
+
if (is_valid_ether_addr(addr)) {
memcpy(dev->net->dev_addr, addr, ETH_ALEN);
} else {
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 376079b9bd75..85d7d8c94905 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -528,6 +528,28 @@ static int s3c64xx_serial_startup(struct uart_port *port)
return ret;
}
+static void s3c64xx_serial_shutdown(struct uart_port *port)
+{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
+ if (ourport->tx_claimed) {
+ free_irq(port->irq, ourport);
+ tx_enabled(port) = 0;
+ ourport->tx_claimed = 0;
+ }
+
+ if (ourport->rx_claimed) {
+ ourport->rx_claimed = 0;
+ rx_enabled(port) = 0;
+ }
+
+ /* Clear pending interrupts and mask all interrupts */
+ if (s3c24xx_serial_has_interrupt_mask(port)) {
+ wr_regl(port, S3C64XX_UINTP, 0xf);
+ wr_regl(port, S3C64XX_UINTM, 0xf);
+ }
+}
+
/* power power management control */
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1013,6 +1035,9 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+ wr_regl(port, S3C64XX_UINTM, 0xf);
+ wr_regl(port, S3C64XX_UINTP, 0xf);
+
/* some delay is required after fifo reset */
udelay(1);
}
@@ -1125,8 +1150,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->dev = &platdev->dev;
/* Startup sequence is different for s3c64xx and higher SoC's */
- if (s3c24xx_serial_has_interrupt_mask(port))
+ if (s3c24xx_serial_has_interrupt_mask(port)) {
s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
+ s3c24xx_serial_ops.shutdown = s3c64xx_serial_shutdown;
+ }
port->uartclk = 1;
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index 12bbede3b091..27985b0852b9 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <video/exynos_dp.h>
@@ -865,13 +866,13 @@ static void exynos_dp_hotplug(struct work_struct *work)
ret = exynos_dp_detect_hpd(dp);
if (ret) {
/* Cable has been disconnected, we're done */
- return;
+ //return;
}
ret = exynos_dp_handle_edid(dp);
if (ret) {
dev_err(dp->dev, "unable to handle edid\n");
- return;
+ //return;
}
ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
@@ -895,11 +896,50 @@ static void exynos_dp_hotplug(struct work_struct *work)
}
#ifdef CONFIG_OF
+static int exynos_parse_gpio(struct device *dev)
+{
+ int gpio = -1;
+ struct device_node *np = dev->of_node;
+ enum of_gpio_flags flags;
+ u32 value;
+ int ret = -1;
+
+ if (!of_find_property(np, "lcd_bl_gpio", &value)) {
+ dev_err(dev, "no bl gpio property found\n");
+ return -1;
+ }
+
+ gpio = of_get_named_gpio_flags(np, "lcd_bl_gpio", 0, &flags);
+ if (gpio_is_valid(gpio)) {
+ ret = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "exynos4-fb");
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ gpio_set_value(gpio, 1);
+
+ if (!of_find_property(np, "lcd_en_gpio", &value)) {
+ dev_err(dev, "no bl gpio property found\n");
+ return -1;
+ }
+ gpio = of_get_named_gpio_flags(np, "lcd_en_gpio", 0, &flags);
+ if (gpio_is_valid(gpio)) {
+ ret = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "exynos4-fb");
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ gpio_set_value(gpio, 1);
+
+ return 0;
+}
+
static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
{
struct device_node *dp_node = dev->of_node;
struct exynos_dp_platdata *pd;
struct video_info *dp_video_config;
+ int ret = -1;
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
if (!pd) {
@@ -960,6 +1000,10 @@ static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
return ERR_PTR(-EINVAL);
}
+ ret = exynos_parse_gpio(dev);
+ if (ret != 0)
+ return NULL;
+
return pd;
}
@@ -1116,6 +1160,8 @@ static int exynos_dp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dp);
+ schedule_work(&dp->hotplug_work);
+
return 0;
}
@@ -1207,7 +1253,21 @@ static struct platform_driver exynos_dp_driver = {
},
};
-module_platform_driver(exynos_dp_driver);
+//module_platform_driver(exynos_dp_driver);
+static int __init exynos_dp_init(void)
+{
+ return platform_driver_probe(&exynos_dp_driver, exynos_dp_probe);
+}
+
+static void __exit exynos_dp_exit(void)
+{
+ platform_driver_unregister(&exynos_dp_driver);
+}
+/* TODO: Register as module_platform_driver */
+/* Currently, we make it late_initcall to make */
+/* sure that s3c-fb is probed before DP driver */
+late_initcall(exynos_dp_init);
+module_exit(exynos_dp_exit);
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Samsung SoC DP Driver");
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
index 32e540600f99..f804d9717510 100644..100755
--- a/drivers/video/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/exynos/exynos_mipi_dsi.c
@@ -33,6 +33,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/err.h>
+#include <linux/lcd.h>
#include <video/exynos_mipi_dsim.h>
@@ -42,6 +43,8 @@
struct mipi_dsim_ddi {
int bus_id;
struct list_head list;
+ struct device_node *ofnode_dsim_lcd_dev;
+ struct device_node *ofnode_dsim_dphy;
struct mipi_dsim_lcd_device *dsim_lcd_dev;
struct mipi_dsim_lcd_driver *dsim_lcd_drv;
};
@@ -180,6 +183,37 @@ static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
return 0;
}
+struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_driver(
+ struct mipi_dsim_lcd_device *lcd_dev)
+{
+ struct mipi_dsim_ddi *dsim_ddi, *next;
+ struct mipi_dsim_lcd_driver *lcd_drv;
+
+ mutex_lock(&mipi_dsim_lock);
+
+ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+ if (!dsim_ddi)
+ goto out;
+
+ lcd_drv = dsim_ddi->dsim_lcd_drv;
+ if (!lcd_drv)
+ continue;
+
+ if ((strcmp(lcd_dev->name, lcd_drv->name)) == 0) {
+
+ mutex_unlock(&mipi_dsim_lock);
+ return dsim_ddi;
+ }
+
+ list_del(&dsim_ddi->list);
+ kfree(dsim_ddi);
+ }
+
+out:
+ mutex_unlock(&mipi_dsim_lock);
+ return NULL;
+}
+
int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
{
struct mipi_dsim_ddi *dsim_ddi;
@@ -189,17 +223,20 @@ int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
return -EFAULT;
}
- dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+ dsim_ddi = exynos_mipi_dsi_find_lcd_driver(lcd_dev);
if (!dsim_ddi) {
- pr_err("failed to allocate dsim_ddi object.\n");
- return -ENOMEM;
+ dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+ if (!dsim_ddi) {
+ pr_err("failed to allocate dsim_ddi object.\n");
+ return -ENOMEM;
+ }
+ mutex_lock(&mipi_dsim_lock);
+ list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+ mutex_unlock(&mipi_dsim_lock);
}
dsim_ddi->dsim_lcd_dev = lcd_dev;
-
- mutex_lock(&mipi_dsim_lock);
- list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
- mutex_unlock(&mipi_dsim_lock);
+ dsim_ddi->bus_id = lcd_dev->bus_id;
return 0;
}
@@ -252,11 +289,26 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
if (!dsim_ddi) {
- pr_err("mipi_dsim_ddi object not found.\n");
- return -EFAULT;
- }
+ /*
+ * If driver specific device is not registered then create a
+ * dsim_ddi object, fill the driver information and add to the
+ * end of the dsim_ddi_list list
+ */
+ dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+ if (!dsim_ddi) {
+ pr_err("failed to allocate dsim_ddi object.\n");
+ return -ENOMEM;
+ }
- dsim_ddi->dsim_lcd_drv = lcd_drv;
+ dsim_ddi->dsim_lcd_drv = lcd_drv;
+
+ mutex_lock(&mipi_dsim_lock);
+ list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+ mutex_unlock(&mipi_dsim_lock);
+
+ } else {
+ dsim_ddi->dsim_lcd_drv = lcd_drv;
+ }
pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
lcd_drv->name);
@@ -328,6 +380,414 @@ static struct mipi_dsim_master_ops master_ops = {
.set_blank_mode = exynos_mipi_dsi_blank_mode,
};
+struct device_node *exynos_mipi_find_ofnode_dsim_phy(
+ struct platform_device *pdev)
+{
+ struct device_node *dn, *dn_dphy;
+ const __be32 *prop;
+
+ dn = pdev->dev.of_node;
+ prop = of_get_property(dn, "mipi-phy", NULL);
+ if (NULL == prop) {
+ dev_err(&pdev->dev, "Could not find property mipi-phy\n");
+ return NULL;
+ }
+
+ dn_dphy = of_find_node_by_phandle(be32_to_cpup(prop));
+ if (NULL == dn_dphy) {
+ dev_err(&pdev->dev, "Could not find node\n");
+ return NULL;
+ }
+
+ return dn_dphy;
+}
+
+struct device_node *exynos_mipi_find_ofnode_lcd_device(
+ struct platform_device *pdev)
+{
+ struct device_node *dn, *dn_lcd_panel;
+ const __be32 *prop;
+
+ dn = pdev->dev.of_node;
+ prop = of_get_property(dn, "mipi-lcd", NULL);
+ if (NULL == prop) {
+ dev_err(&pdev->dev, "could not find property mipi-lcd\n");
+ return NULL;
+ }
+
+ dn_lcd_panel = of_find_node_by_phandle(be32_to_cpup(prop));
+ if (NULL == dn_lcd_panel) {
+ dev_err(&pdev->dev, "could not find node\n");
+ return NULL;
+ }
+
+ return dn_lcd_panel;
+}
+
+static void exynos_mipi_dsim_enable_d_phy_type1(
+ struct platform_device *pdev,
+ bool enable)
+{
+ struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
+ platform_get_drvdata(pdev);
+ struct mipi_dsim_phy_config_type1 *dphy_cfg_type1 =
+ &dsim->dsim_phy_config->phy_cfg_type1;
+ u32 reg_enable;
+
+ reg_enable = __raw_readl(dphy_cfg_type1->reg_enable_dphy);
+ reg_enable &= ~(dphy_cfg_type1->ctrlbit_enable_dphy);
+
+ if (enable)
+ reg_enable |= dphy_cfg_type1->ctrlbit_enable_dphy;
+
+ __raw_writel(reg_enable, dphy_cfg_type1->reg_enable_dphy);
+}
+
+static void exynos_mipi_dsim_reset_type1(
+ struct platform_device *pdev,
+ bool enable)
+{
+ struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
+ platform_get_drvdata(pdev);
+ struct mipi_dsim_phy_config_type1 *dphy_cfg_type1 =
+ &dsim->dsim_phy_config->phy_cfg_type1;
+ u32 reg_reset;
+
+ reg_reset = __raw_readl(dphy_cfg_type1->reg_reset_dsim);
+ reg_reset &= ~(dphy_cfg_type1->ctrlbit_reset_dsim);
+
+ if (enable)
+ reg_reset |= dphy_cfg_type1->ctrlbit_reset_dsim;
+
+ __raw_writel(reg_reset, dphy_cfg_type1->reg_reset_dsim);
+}
+
+static int exynos_mipi_dsim_phy_init_type1(
+ struct platform_device *pdev,
+ bool on_off)
+{
+ exynos_mipi_dsim_enable_d_phy_type1(pdev, on_off);
+ exynos_mipi_dsim_reset_type1(pdev, on_off);
+ return 0;
+}
+
+static int exynos_mipi_parse_ofnode_dsim_phy_type1(
+ struct platform_device *pdev,
+ struct mipi_dsim_phy_config_type1 *dphy_cfg_type1,
+ struct device_node *np)
+{
+ struct mipi_dsim_device *dsim = (struct mipi_dsim_device *)
+ platform_get_drvdata(pdev);
+ u32 paddr_phy_enable, paddr_dsim_reset;
+
+ if (of_property_read_u32(np, "reg_enable_dphy", &paddr_phy_enable))
+ return -EINVAL;
+
+ dphy_cfg_type1->reg_enable_dphy = ioremap(paddr_phy_enable, SZ_4);
+ if (!dphy_cfg_type1->reg_enable_dphy)
+ return -EINVAL;
+
+ if (of_property_read_u32(np, "reg_reset_dsim", &paddr_dsim_reset))
+ return -EINVAL;
+
+ dphy_cfg_type1->reg_reset_dsim = ioremap(paddr_dsim_reset, SZ_4);
+ if (!dphy_cfg_type1->reg_reset_dsim)
+ goto err_ioremap_01;
+
+ if (of_property_read_u32(np, "mask_enable_dphy",
+ &dphy_cfg_type1->ctrlbit_enable_dphy))
+ goto err_ioremap_02;
+
+ if (of_property_read_u32(np, "mask_reset_dsim",
+ &dphy_cfg_type1->ctrlbit_reset_dsim))
+ goto err_ioremap_02;
+
+ dsim->pd->phy_enable = exynos_mipi_dsim_phy_init_type1;
+
+ return 0;
+
+err_ioremap_02:
+ iounmap(dphy_cfg_type1->reg_reset_dsim);
+
+err_ioremap_01:
+ iounmap(dphy_cfg_type1->reg_enable_dphy);
+ return -EINVAL;
+}
+
+static struct mipi_dsim_phy_config *exynos_mipi_parse_ofnode_dsim_phy(
+ struct platform_device *pdev,
+ struct device_node *np)
+{
+ struct mipi_dsim_phy_config *mipi_dphy_config;
+ const char *compatible;
+
+ mipi_dphy_config = devm_kzalloc(&pdev->dev,
+ sizeof(struct mipi_dsim_phy_config), GFP_KERNEL);
+ if (!mipi_dphy_config) {
+ dev_err(&pdev->dev,
+ "failed to allocate mipi_dsim_phy_config object.\n");
+ return NULL;
+ }
+
+ if (of_property_read_string(np, "compatible", &compatible)) {
+ dev_err(&pdev->dev, "compatible property not found");
+ return NULL;
+ }
+
+ if (!strcmp(compatible, "samsung-exynos,mipi-phy-type1"))
+ mipi_dphy_config->type = MIPI_DSIM_PHY_CONFIG_TYPE1;
+ else
+ mipi_dphy_config->type = -1;
+
+ switch (mipi_dphy_config->type) {
+ case MIPI_DSIM_PHY_CONFIG_TYPE1:
+ if (exynos_mipi_parse_ofnode_dsim_phy_type1(
+ pdev, &mipi_dphy_config->phy_cfg_type1, np))
+ return NULL;
+ break;
+ default:
+ dev_err(&pdev->dev, "mipi phy - unknown type");
+ return NULL;
+ }
+
+ return mipi_dphy_config;
+}
+
+static struct mipi_dsim_lcd_device *exynos_mipi_parse_ofnode_lcd(
+ struct platform_device *pdev, struct device_node *np)
+{
+ struct mipi_dsim_lcd_device *active_mipi_dsim_lcd_device;
+ struct lcd_platform_data *active_lcd_platform_data;
+ const char *lcd_name;
+
+ active_mipi_dsim_lcd_device = devm_kzalloc(&pdev->dev,
+ sizeof(struct mipi_dsim_lcd_device), GFP_KERNEL);
+ if (!active_mipi_dsim_lcd_device) {
+ dev_err(&pdev->dev,
+ "failed to allocate active_mipi_dsim_lcd_device object.\n");
+ return NULL;
+ }
+
+ if (of_property_read_string(np, "lcd-name", &lcd_name)) {
+ dev_err(&pdev->dev, "lcd name property not found");
+ return NULL;
+ }
+
+ active_mipi_dsim_lcd_device->name = (char *)lcd_name;
+
+ if (of_property_read_u32(np, "id", &active_mipi_dsim_lcd_device->id))
+ active_mipi_dsim_lcd_device->id = -1;
+
+ if (of_property_read_u32(np, "bus-id",
+ &active_mipi_dsim_lcd_device->bus_id))
+ active_mipi_dsim_lcd_device->bus_id = -1;
+
+ active_lcd_platform_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct lcd_platform_data), GFP_KERNEL);
+ if (!active_lcd_platform_data) {
+ dev_err(&pdev->dev,
+ "failed to allocate active_lcd_platform_data object.\n");
+ return NULL;
+ }
+
+ /* store the lcd node pointer for futher use in lcd driver */
+ active_lcd_platform_data->pdata = (void *) np;
+ active_mipi_dsim_lcd_device->platform_data =
+ (void *)active_lcd_platform_data;
+
+ return active_mipi_dsim_lcd_device;
+}
+
+static int exynos_mipi_parse_ofnode_config(struct platform_device *pdev,
+ struct device_node *np, struct mipi_dsim_config *dsim_config)
+{
+ unsigned int u32Val;
+
+ if (of_property_read_u32(np, "e_interface", &u32Val)) {
+ dev_err(&pdev->dev, "e_interface property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->e_interface = (enum mipi_dsim_interface_type)u32Val;
+
+ if (of_property_read_u32(np, "e_pixel_format", &u32Val)) {
+ dev_err(&pdev->dev, "e_pixel_format property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->e_pixel_format = (enum mipi_dsim_pixel_format)u32Val;
+
+ if (of_property_read_u32(np, "auto_flush", &u32Val)) {
+ dev_err(&pdev->dev, "auto_flush property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->auto_flush = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "eot_disable", &u32Val)) {
+ dev_err(&pdev->dev, "eot_disable property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->eot_disable = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "auto_vertical_cnt", &u32Val)) {
+ dev_err(&pdev->dev, "auto_vertical_cnt property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->auto_vertical_cnt = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "hse", &u32Val)) {
+ dev_err(&pdev->dev, "hse property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->hse = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "hfp", &u32Val)) {
+ dev_err(&pdev->dev, "hfp property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->hfp = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "hbp", &u32Val)) {
+ dev_err(&pdev->dev, "hbp property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->hbp = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "hsa", &u32Val)) {
+ dev_err(&pdev->dev, "hsa property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->hsa = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "e_no_data_lane", &u32Val)) {
+ dev_err(&pdev->dev, "e_no_data_lane property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->e_no_data_lane = (enum mipi_dsim_no_of_data_lane)u32Val;
+
+ if (of_property_read_u32(np, "e_byte_clk", &u32Val)) {
+ dev_err(&pdev->dev, "e_byte_clk property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->e_byte_clk = (enum mipi_dsim_byte_clk_src)u32Val;
+
+ if (of_property_read_u32(np, "e_burst_mode", &u32Val)) {
+ dev_err(&pdev->dev, "e_burst_mode property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->e_burst_mode = (enum mipi_dsim_burst_mode_type)u32Val;
+
+ if (of_property_read_u32(np, "p", &u32Val)) {
+ dev_err(&pdev->dev, "p property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->p = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "m", &u32Val)) {
+ dev_err(&pdev->dev, "m property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->m = (unsigned short)u32Val;
+
+ if (of_property_read_u32(np, "s", &u32Val)) {
+ dev_err(&pdev->dev, "s property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->s = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "pll_stable_time", &u32Val)) {
+ dev_err(&pdev->dev, "pll_stable_time property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->pll_stable_time = (unsigned int)u32Val;
+
+ if (of_property_read_u32(np, "esc_clk", &u32Val)) {
+ dev_err(&pdev->dev, "esc_clk property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->esc_clk = (unsigned long)u32Val;
+
+ if (of_property_read_u32(np, "stop_holding_cnt", &u32Val)) {
+ dev_err(&pdev->dev, "stop_holding_cnt property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->stop_holding_cnt = (unsigned short)u32Val;
+
+ if (of_property_read_u32(np, "bta_timeout", &u32Val)) {
+ dev_err(&pdev->dev, "bta_timeout property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->bta_timeout = (unsigned char)u32Val;
+
+ if (of_property_read_u32(np, "rx_timeout", &u32Val)) {
+ dev_err(&pdev->dev, "rx_timeout property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->rx_timeout = (unsigned short)u32Val;
+
+ if (of_property_read_u32(np, "e_virtual_ch", &u32Val)) {
+ dev_err(&pdev->dev, "e_virtual_ch property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->e_virtual_ch = (enum mipi_dsim_virtual_ch_no)u32Val;
+
+ if (of_property_read_u32(np, "cmd_allow", &u32Val)) {
+ dev_err(&pdev->dev, "cmd_allow property not found\n");
+ return -EINVAL;
+ }
+ dsim_config->cmd_allow = (unsigned char)u32Val;
+
+ return 0;
+}
+
+static int exynos_mipi_parse_ofnode_panel_info(struct platform_device *pdev,
+ struct device_node *np, struct fb_videomode *panel_info)
+{
+ unsigned int data[4];
+
+ if (of_property_read_u32_array(np, "lcd-htiming", data, 4)) {
+ dev_err(&pdev->dev, "invalid horizontal timing\n");
+ return -EINVAL;
+ }
+ panel_info->left_margin = data[0];
+ panel_info->right_margin = data[1];
+ panel_info->hsync_len = data[2];
+ panel_info->xres = data[3];
+
+ if (of_property_read_u32_array(np, "lcd-vtiming", data, 4)) {
+ dev_err(&pdev->dev, "invalid vertical timing\n");
+ return -EINVAL;
+ }
+ panel_info->upper_margin = data[0];
+ panel_info->lower_margin = data[1];
+ panel_info->vsync_len = data[2];
+ panel_info->yres = data[3];
+
+ return 0;
+}
+
+static int exynos_mipi_parse_ofnode(struct platform_device *pdev,
+ struct mipi_dsim_config *dsim_config, struct fb_videomode *panel_info)
+{
+ struct device_node *np_dsim_config, *np_panel_info;
+ struct device_node *np = pdev->dev.of_node;
+
+ np_dsim_config = of_find_node_by_name(np, "mipi-config");
+ if (!np_dsim_config)
+ return -EINVAL;
+
+ if (exynos_mipi_parse_ofnode_config(pdev, np_dsim_config, dsim_config))
+ return -EINVAL;
+
+ np_panel_info = of_parse_phandle(np, "panel-info", 0);
+ if (!np_panel_info)
+ return -EINVAL;
+
+ if (exynos_mipi_parse_ofnode_panel_info(pdev,
+ np_panel_info, panel_info))
+ return -EINVAL;
+
+ return 0;
+}
+
static int exynos_mipi_dsi_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -335,6 +795,12 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
struct mipi_dsim_config *dsim_config;
struct mipi_dsim_platform_data *dsim_pd;
struct mipi_dsim_ddi *dsim_ddi;
+ struct device_node *ofnode_lcd = NULL;
+ struct device_node *ofnode_dphy = NULL;
+ struct mipi_dsim_lcd_device *active_mipi_dsim_lcd_device = NULL;
+ struct mipi_dsim_phy_config *mipi_dphy_config;
+ struct fb_videomode *panel_info;
+ unsigned int u32Val;
int ret = -EINVAL;
dsim = devm_kzalloc(&pdev->dev, sizeof(struct mipi_dsim_device),
@@ -344,21 +810,86 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ if (pdev->dev.of_node) {
+ ofnode_lcd = exynos_mipi_find_ofnode_lcd_device(pdev);
+ if (!ofnode_lcd)
+ return -EINVAL;
+
+ active_mipi_dsim_lcd_device =
+ exynos_mipi_parse_ofnode_lcd(pdev, ofnode_lcd);
+
+ if (NULL == active_mipi_dsim_lcd_device)
+ return -EINVAL;
+
+ if (NULL == exynos_mipi_dsi_find_lcd_driver(
+ active_mipi_dsim_lcd_device))
+ return -EPROBE_DEFER;
+
+ exynos_mipi_dsi_register_lcd_device(
+ active_mipi_dsim_lcd_device);
+ }
+
dsim->pd = to_dsim_plat(pdev);
dsim->dev = &pdev->dev;
dsim->id = pdev->id;
- /* get mipi_dsim_platform_data. */
- dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
- if (dsim_pd == NULL) {
- dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
- return -EINVAL;
- }
- /* get mipi_dsim_config. */
- dsim_config = dsim_pd->dsim_config;
- if (dsim_config == NULL) {
- dev_err(&pdev->dev, "failed to get dsim config data.\n");
- return -EINVAL;
+ if (pdev->dev.of_node) {
+ dsim_config = devm_kzalloc(&pdev->dev,
+ sizeof(struct mipi_dsim_config), GFP_KERNEL);
+ if (!dsim_config) {
+ dev_err(&pdev->dev,
+ "failed to allocate dsim_config object.\n");
+ return -ENOMEM;
+ }
+
+ panel_info = devm_kzalloc(&pdev->dev,
+ sizeof(struct fb_videomode), GFP_KERNEL);
+ if (!panel_info) {
+ dev_err(&pdev->dev,
+ "failed to allocate fb_videomode object.\n");
+ return -ENOMEM;
+ }
+
+ /* parse the mipi of_node for dism_config and panel info. */
+ if (exynos_mipi_parse_ofnode(pdev, dsim_config, panel_info)) {
+ dev_err(&pdev->dev,
+ "failed to read mipi-config, panel-info\n");
+ return -EINVAL;
+ }
+
+ dsim_pd = devm_kzalloc(&pdev->dev,
+ sizeof(struct mipi_dsim_platform_data), GFP_KERNEL);
+ if (!dsim_pd) {
+ dev_err(&pdev->dev,
+ "failed to allocate mipi_dsim_platform_data\n");
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u32(pdev->dev.of_node, "enabled", &u32Val))
+ dev_err(&pdev->dev, "enabled property not found\n");
+ else
+ dsim_pd->enabled = !(!u32Val);
+
+ dsim_pd->lcd_panel_info = (void *)panel_info;
+ dsim_pd->dsim_config = dsim_config;
+ dsim->pd = dsim_pd;
+
+ } else {
+ /* get mipi_dsim_platform_data. */
+ dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+ if (dsim_pd == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get platform data for dsim.\n");
+ return -EFAULT;
+ }
+
+ /* get mipi_dsim_config. */
+ dsim_config = dsim_pd->dsim_config;
+ if (dsim_config == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get dsim config data.\n");
+ return -EFAULT;
+ }
}
dsim->dsim_config = dsim_config;
@@ -379,7 +910,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
return -ENODEV;
}
- clk_enable(dsim->clock);
+ clk_prepare_enable(dsim->clock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -392,12 +923,22 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
mutex_init(&dsim->lock);
/* bind lcd ddi matched with panel name. */
- dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
+ if (pdev->dev.of_node) {
+ dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim,
+ active_mipi_dsim_lcd_device->name);
+ } else {
+ dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim,
+ dsim_pd->lcd_panel_name);
+ }
+
if (!dsim_ddi) {
dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
- ret = -EINVAL;
+ ret = -ENXIO;
goto error;
- }
+ } else if (pdev->dev.of_node) {
+ dsim_ddi->ofnode_dsim_lcd_dev = ofnode_lcd;
+ dsim_ddi->ofnode_dsim_dphy = ofnode_dphy;
+ }
dsim->irq = platform_get_irq(pdev, 0);
if (IS_ERR_VALUE(dsim->irq)) {
@@ -410,6 +951,20 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
init_completion(&dsim_rd_comp);
platform_set_drvdata(pdev, dsim);
+ /* update dsim phy config node */
+ if (pdev->dev.of_node) {
+ ofnode_dphy = exynos_mipi_find_ofnode_dsim_phy(pdev);
+ if (!ofnode_dphy)
+ return -EINVAL;
+
+ mipi_dphy_config = exynos_mipi_parse_ofnode_dsim_phy(pdev,
+ ofnode_dphy);
+ if (NULL == mipi_dphy_config)
+ return -EINVAL;
+
+ dsim->dsim_phy_config = mipi_dphy_config;
+ }
+
ret = devm_request_irq(&pdev->dev, dsim->irq,
exynos_mipi_dsi_interrupt_handler,
IRQF_SHARED, dev_name(&pdev->dev), dsim);
@@ -444,10 +999,22 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
exynos_mipi_update_cfg(dsim);
+ /* enable the LPDT mode */
+ exynos_mipi_dsi_stand_by(dsim, 0);
+ exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 1);
+ exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 1);
+ exynos_mipi_dsi_enable_hs_clock(dsim, 0);
+
/* set lcd panel sequence commands. */
if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
+ /* enable the HS mode */
+ exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+ exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ exynos_mipi_dsi_enable_hs_clock(dsim, 1);
+ exynos_mipi_dsi_stand_by(dsim, 1);
+
dsim->suspended = false;
done:
@@ -557,13 +1124,33 @@ static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume)
};
+static struct platform_device_id exynos_mipi_driver_ids[] = {
+ {
+ .name = "exynos-mipidsim",
+ .driver_data = (unsigned long)0,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, exynos_mipi_driver_ids);
+
+static const struct of_device_id exynos_mipi_match[] = {
+ {
+ .compatible = "samsung,exynos-mipidsim",
+ .data = NULL,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_mipi_match);
+
static struct platform_driver exynos_mipi_dsi_driver = {
.probe = exynos_mipi_dsi_probe,
.remove = exynos_mipi_dsi_remove,
+ .id_table = exynos_mipi_driver_ids,
.driver = {
.name = "exynos-mipi-dsim",
.owner = THIS_MODULE,
.pm = &exynos_mipi_dsi_pm_ops,
+ .of_match_table = exynos_mipi_match,
},
};
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c
index 520fc9bd887b..c54ebb6407e8 100644
--- a/drivers/video/exynos/exynos_mipi_dsi_common.c
+++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
@@ -718,7 +718,7 @@ int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
/* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
if (dsim_config->e_interface == (u32) DSIM_VIDEO) {
- if (dsim_config->auto_vertical_cnt == 0) {
+
exynos_mipi_dsi_set_main_disp_vporch(dsim,
dsim_config->cmd_allow,
timing->lower_margin,
@@ -729,7 +729,6 @@ int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
exynos_mipi_dsi_set_main_disp_sync_area(dsim,
timing->vsync_len,
timing->hsync_len);
- }
}
exynos_mipi_dsi_set_main_disp_resol(dsim, timing->xres,
diff --git a/drivers/video/exynos/s6e8ax0.c b/drivers/video/exynos/s6e8ax0.c
index ca2602413aa4..2e3f3442abd5 100644..100755
--- a/drivers/video/exynos/s6e8ax0.c
+++ b/drivers/video/exynos/s6e8ax0.c
@@ -1,9 +1,9 @@
-/* linux/drivers/video/exynos/s6e8ax0.c
+/* linux/drivers/video/exynos/s6e8aa0.c
*
- * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
+ * MIPI-DSI based s6e8aa0 AMOLED lcd 4.65 inch panel driver.
+ * This driver is implemented according to the s6e8ax0 panel driver.
*
- * Inki Dae, <inki.dae@samsung.com>
- * Donghwa Lee, <dh09.lee@samsung.com>
+ * Shaik Ameer Basha <shaik.ameer@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,7 @@
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
#include <video/mipi_display.h>
#include <video/exynos_mipi_dsim.h>
@@ -31,7 +32,7 @@
#define LDI_MTP_LENGTH 24
#define DSIM_PM_STABLE_TIME 10
#define MIN_BRIGHTNESS 0
-#define MAX_BRIGHTNESS 24
+#define MAX_BRIGHTNESS 26
#define GAMMA_TABLE_COUNT 26
#define POWER_IS_ON(pwr) ((pwr) == FB_BLANK_UNBLANK)
@@ -40,6 +41,7 @@
#define lcd_to_master(a) (a->dsim_dev->master)
#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
+#define lcd_to_master_ver(a) ((lcd_to_master(a))->version)
enum {
DSIM_NONE_STATE = 0,
@@ -47,13 +49,14 @@ enum {
DSIM_FRAME_DONE = 2,
};
-struct s6e8ax0 {
+struct s6e8aa0 {
struct device *dev;
+ unsigned int gpio_reset;
+ unsigned int gpio_power;
+ unsigned int gpio_bl;
unsigned int power;
unsigned int id;
unsigned int gamma;
- unsigned int acl_enable;
- unsigned int cur_acl;
struct lcd_device *ld;
struct backlight_device *bd;
@@ -64,13 +67,15 @@ struct s6e8ax0 {
bool enabled;
};
+static struct s6e8aa0 *lcd_global;
+
static struct regulator_bulk_data supplies[] = {
{ .supply = "vdd3", },
{ .supply = "vci", },
};
-static void s6e8ax0_regulator_enable(struct s6e8ax0 *lcd)
+static void s6e8aa0_regulator_enable(struct s6e8aa0 *lcd)
{
int ret = 0;
struct lcd_platform_data *pd = NULL;
@@ -89,7 +94,7 @@ out:
mutex_unlock(&lcd->lock);
}
-static void s6e8ax0_regulator_disable(struct s6e8ax0 *lcd)
+static void s6e8aa0_regulator_disable(struct s6e8aa0 *lcd)
{
int ret = 0;
@@ -105,194 +110,275 @@ out:
mutex_unlock(&lcd->lock);
}
-static const unsigned char s6e8ax0_22_gamma_30[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
- 0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
- 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
-};
-
-static const unsigned char s6e8ax0_22_gamma_50[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
- 0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
- 0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
-};
-
-static const unsigned char s6e8ax0_22_gamma_60[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
- 0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
- 0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
-};
-static const unsigned char s6e8ax0_22_gamma_70[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
- 0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
- 0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
+static const unsigned char gamma22_30[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xDF, 0x86, 0xF5,
+ 0xD5, 0xC7, 0xCF, 0xDF, 0xE0, 0xE0,
+ 0xC9, 0xC9, 0xCC, 0xD7, 0xD6, 0xD5,
+ 0x00, 0x68, 0x00, 0x68, 0x00, 0x75,
};
-static const unsigned char s6e8ax0_22_gamma_80[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
- 0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
- 0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
+static const unsigned char gamma22_40[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xE5, 0xAA, 0xF2,
+ 0xD6, 0xCC, 0xCF, 0xE0, 0xE2, 0xE2,
+ 0xC8, 0xC9, 0xCA, 0xD2, 0xD2, 0xCF,
+ 0x00, 0x71, 0x00, 0x70, 0x00, 0x80,
};
-static const unsigned char s6e8ax0_22_gamma_90[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
- 0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
- 0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
+static const unsigned char gamma22_50[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xE7, 0xBB, 0xEE,
+ 0xD6, 0xCE, 0xD0, 0xE0, 0xE3, 0xE4,
+ 0xC5, 0xC4, 0xC5, 0xD2, 0xD2, 0xCF,
+ 0x00, 0x78, 0x00, 0x78, 0x00, 0x88,
};
-static const unsigned char s6e8ax0_22_gamma_100[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
- 0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
- 0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
+static const unsigned char gamma22_60[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xE9, 0xC4, 0xEB,
+ 0xD6, 0xD0, 0xD1, 0xE0, 0xE3, 0xE4,
+ 0xC3, 0xC2, 0xC2, 0xD2, 0xD1, 0xCF,
+ 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x8F,
};
-static const unsigned char s6e8ax0_22_gamma_120[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
- 0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
- 0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
+static const unsigned char gamma22_70[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEA, 0xC9, 0xEA,
+ 0xD6, 0xD2, 0xD2, 0xDF, 0xE1, 0xE3,
+ 0xC2, 0xC1, 0xC0, 0xD1, 0xD0, 0xCE,
+ 0x00, 0x84, 0x00, 0x84, 0x00, 0x96,
};
-static const unsigned char s6e8ax0_22_gamma_130[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
- 0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
- 0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
+static const unsigned char gamma22_80[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEB, 0xCC, 0xE9,
+ 0xD5, 0xD4, 0xD3, 0xDE, 0xE1, 0xE2,
+ 0xC2, 0xBF, 0xBF, 0xCF, 0xCF, 0xCC,
+ 0x00, 0x89, 0x00, 0x89, 0x00, 0x9C,
};
-static const unsigned char s6e8ax0_22_gamma_140[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
- 0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
- 0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
+static const unsigned char gamma22_90[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEB, 0xD0, 0xE9,
+ 0xD4, 0xD5, 0xD4, 0xDF, 0xE0, 0xE1,
+ 0xC1, 0xBE, 0xBD, 0xCD, 0xCD, 0xCA,
+ 0x00, 0x8E, 0x00, 0x8F, 0x00, 0xA2,
};
-static const unsigned char s6e8ax0_22_gamma_150[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
- 0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
- 0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
+static const unsigned char gamma22_100[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEA, 0xD2, 0xE7,
+ 0xD7, 0xD6, 0xD6, 0xDF, 0xDF, 0xE2,
+ 0xBF, 0xBD, 0xBC, 0xCD, 0xCD, 0xC9,
+ 0x00, 0x92, 0x00, 0x93, 0x00, 0xA7,
};
-static const unsigned char s6e8ax0_22_gamma_160[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
- 0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
- 0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
+static const unsigned char gamma22_110[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEB, 0xD4, 0xE5,
+ 0xD6, 0xD6, 0xD7, 0xDE, 0xDF, 0xE0,
+ 0xBE, 0xBC, 0xBB, 0xCE, 0xCC, 0xC9,
+ 0x00, 0x96, 0x00, 0x97, 0x00, 0xAC,
};
-static const unsigned char s6e8ax0_22_gamma_170[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
- 0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
- 0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
+static const unsigned char gamma22_120[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xD6, 0xE6,
+ 0xD6, 0xD7, 0xD8, 0xDE, 0xDE, 0xE0,
+ 0xBC, 0xBC, 0xB9, 0xCD, 0xCA, 0xC8,
+ 0x00, 0x9A, 0x00, 0x9C, 0x00, 0xB1,
};
-static const unsigned char s6e8ax0_22_gamma_180[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
- 0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
- 0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
+static const unsigned char gamma22_130[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xD7, 0xE6,
+ 0xD3, 0xD8, 0xD7, 0xDE, 0xDD, 0xDF,
+ 0xBD, 0xBB, 0xB8, 0xCA, 0xC9, 0xC6,
+ 0x00, 0x9F, 0x00, 0xA0, 0x00, 0xB7,
};
-static const unsigned char s6e8ax0_22_gamma_190[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
- 0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
- 0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
+static const unsigned char gamma22_140[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xD9, 0xE5,
+ 0xD4, 0xD8, 0xD9, 0xDE, 0xDD, 0xDF,
+ 0xBB, 0xB9, 0xB7, 0xCA, 0xC9, 0xC5,
+ 0x00, 0xA3, 0x00, 0xA4, 0x00, 0xBB,
};
-static const unsigned char s6e8ax0_22_gamma_200[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
- 0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
- 0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
+static const unsigned char gamma22_150[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xDA, 0xE5,
+ 0xD4, 0xD8, 0xD9, 0xDD, 0xDD, 0xDD,
+ 0xBB, 0xB9, 0xB6, 0xC9, 0xC7, 0xC5,
+ 0x00, 0xA6, 0x00, 0xA8, 0x00, 0xBF,
};
-static const unsigned char s6e8ax0_22_gamma_210[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
- 0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
- 0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
+static const unsigned char gamma22_160[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xDB, 0xE6,
+ 0xD4, 0xD7, 0xD9, 0xDC, 0xDD, 0xDD,
+ 0xB9, 0xB8, 0xB4, 0xC9, 0xC6, 0xC4,
+ 0x00, 0xAA, 0x00, 0xAC, 0x00, 0xC4,
};
-static const unsigned char s6e8ax0_22_gamma_220[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
- 0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
- 0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
+static const unsigned char gamma22_170[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xDC, 0xE5,
+ 0xD5, 0xD8, 0xD9, 0xDD, 0xDC, 0xDD,
+ 0xBA, 0xB7, 0xB5, 0xC7, 0xC6, 0xC3,
+ 0x00, 0xAD, 0x00, 0xAF, 0x00, 0xC7,
};
-static const unsigned char s6e8ax0_22_gamma_230[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
- 0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
- 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
+static const unsigned char gamma22_180[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEE, 0xDD, 0xE6,
+ 0xD4, 0xD7, 0xD9, 0xDB, 0xDC, 0xDB,
+ 0xB9, 0xB7, 0xB4, 0xC6, 0xC4, 0xC2,
+ 0x00, 0xB1, 0x00, 0xB3, 0x00, 0xCC,
};
-static const unsigned char s6e8ax0_22_gamma_240[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
- 0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
- 0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
-};
-
-static const unsigned char s6e8ax0_22_gamma_250[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
- 0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
- 0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
-};
-
-static const unsigned char s6e8ax0_22_gamma_260[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
- 0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
- 0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
-};
-
-static const unsigned char s6e8ax0_22_gamma_270[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
- 0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
- 0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
-};
-
-static const unsigned char s6e8ax0_22_gamma_280[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
- 0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
- 0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
-};
-
-static const unsigned char s6e8ax0_22_gamma_300[] = {
- 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
- 0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
- 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
-};
-
-static const unsigned char *s6e8ax0_22_gamma_table[] = {
- s6e8ax0_22_gamma_30,
- s6e8ax0_22_gamma_50,
- s6e8ax0_22_gamma_60,
- s6e8ax0_22_gamma_70,
- s6e8ax0_22_gamma_80,
- s6e8ax0_22_gamma_90,
- s6e8ax0_22_gamma_100,
- s6e8ax0_22_gamma_120,
- s6e8ax0_22_gamma_130,
- s6e8ax0_22_gamma_140,
- s6e8ax0_22_gamma_150,
- s6e8ax0_22_gamma_160,
- s6e8ax0_22_gamma_170,
- s6e8ax0_22_gamma_180,
- s6e8ax0_22_gamma_190,
- s6e8ax0_22_gamma_200,
- s6e8ax0_22_gamma_210,
- s6e8ax0_22_gamma_220,
- s6e8ax0_22_gamma_230,
- s6e8ax0_22_gamma_240,
- s6e8ax0_22_gamma_250,
- s6e8ax0_22_gamma_260,
- s6e8ax0_22_gamma_270,
- s6e8ax0_22_gamma_280,
- s6e8ax0_22_gamma_300,
-};
-
-static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
+static const unsigned char gamma22_190[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xDE, 0xE6,
+ 0xD3, 0xD8, 0xD8, 0xDD, 0xDB, 0xDC,
+ 0xB9, 0xB6, 0xB4, 0xC5, 0xC4, 0xC0,
+ 0x00, 0xB4, 0x00, 0xB6, 0x00, 0xD0,
+};
+
+static const unsigned char gamma22_200[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xDF, 0xE6,
+ 0xD3, 0xD7, 0xD8, 0xDB, 0xDB, 0xDA,
+ 0xB8, 0xB6, 0xB3, 0xC4, 0xC3, 0xC0,
+ 0x00, 0xB8, 0x00, 0xB9, 0x00, 0xD4,
+};
+
+static const unsigned char gamma22_210[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xE0, 0xE5,
+ 0xD5, 0xD7, 0xD9, 0xDB, 0xDA, 0xDA,
+ 0xB7, 0xB5, 0xB1, 0xC4, 0xC2, 0xC0,
+ 0x00, 0xBA, 0x00, 0xBD, 0x00, 0xD7,
+};
+
+static const unsigned char gamma22_220[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xE0, 0xE6,
+ 0xD4, 0xD7, 0xD9, 0xDA, 0xDA, 0xD9,
+ 0xB7, 0xB4, 0xB1, 0xC2, 0xC2, 0xBE,
+ 0x00, 0xBE, 0x00, 0xC0, 0x00, 0xDC,
+};
+
+static const unsigned char gamma22_230[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xE2, 0xE6,
+ 0xD3, 0xD6, 0xD8, 0xDC, 0xD9, 0xD9,
+ 0xB6, 0xB4, 0xB1, 0xC1, 0xC1, 0xBD,
+ 0x00, 0xC1, 0x00, 0xC3, 0x00, 0xDF,
+};
+
+static const unsigned char gamma22_240[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xE2, 0xE6,
+ 0xD4, 0xD6, 0xD8, 0xDA, 0xDA, 0xDA,
+ 0xB6, 0xB3, 0xB0, 0xC1, 0xBF, 0xBC,
+ 0x00, 0xC4, 0x00, 0xC7, 0x00, 0xE3,
+};
+
+static const unsigned char gamma22_250[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xE3, 0xE7,
+ 0xD4, 0xD6, 0xD8, 0xDB, 0xD9, 0xD9,
+ 0xB3, 0xB2, 0xAE, 0xC1, 0xC0, 0xBC,
+ 0x00, 0xC7, 0x00, 0xC9, 0x00, 0xE7,
+};
+
+static const unsigned char gamma22_260[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xE4, 0xE7,
+ 0xD4, 0xD5, 0xD7, 0xDA, 0xD9, 0xD9,
+ 0xB3, 0xB2, 0xAD, 0xC1, 0xBE, 0xBC,
+ 0x00, 0xC9, 0x00, 0xCD, 0x00, 0xEA,
+};
+
+static const unsigned char gamma22_270[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xE5, 0xE8,
+ 0xD3, 0xD5, 0xD5, 0xDB, 0xD9, 0xD9,
+ 0xB3, 0xB1, 0xAE, 0xBF, 0xBE, 0xBA,
+ 0x00, 0xCC, 0x00, 0xD0, 0x00, 0xEE,
+};
+
+static const unsigned char gamma22_280[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xE5, 0xE6,
+ 0xD2, 0xD4, 0xD6, 0xDA, 0xD9, 0xD8,
+ 0xB3, 0xB1, 0xAD, 0xBF, 0xBD, 0xBA,
+ 0x00, 0xCF, 0x00, 0xD3, 0x00, 0xF1,
+};
+
+static const unsigned char gamma22_290[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xEC, 0xE6, 0xE7,
+ 0xD2, 0xD4, 0xD5, 0xDB, 0xD8, 0xD8,
+ 0xB1, 0xB0, 0xAC, 0xBE, 0xBD, 0xB9,
+ 0x00, 0xD3, 0x00, 0xD6, 0x00, 0xF5,
+};
+
+static const unsigned char gamma22_300[] = {
+ 0xFA, 0x01,
+ 0x1F, 0x1F, 0x1F, 0xED, 0xE6, 0xE7,
+ 0xD1, 0xD3, 0xD4, 0xDA, 0xD8, 0xD7,
+ 0xB1, 0xAF, 0xAB, 0xBD, 0xBB, 0xB8,
+ 0x00, 0xD6, 0x00, 0xDA, 0x00, 0xFA,
+};
+
+
+static const unsigned char *s6e8aa0_22_gamma_table[] = {
+ gamma22_30,
+ gamma22_40,
+ gamma22_50,
+ gamma22_60,
+ gamma22_70,
+ gamma22_80,
+ gamma22_90,
+ gamma22_100,
+ gamma22_110,
+ gamma22_120,
+ gamma22_130,
+ gamma22_140,
+ gamma22_150,
+ gamma22_160,
+ gamma22_170,
+ gamma22_180,
+ gamma22_190,
+ gamma22_200,
+ gamma22_210,
+ gamma22_220,
+ gamma22_230,
+ gamma22_240,
+ gamma22_250,
+ gamma22_260,
+ gamma22_270,
+ gamma22_280,
+ gamma22_290,
+};
+
+static void s6e8aa0_panel_cond(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
- 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
- 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
- 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
+ 0xF8,
+ 0x25, 0x34, 0x00, 0x00, 0x00, 0x95, 0x00, 0x3c, 0x7d, 0x08,
+ 0x27, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x63, 0xc0, 0xc1,
+ 0x01, 0x81, 0xc1, 0x00, 0xc8, 0xc1, 0xd3, 0x01
+
};
+
static const unsigned char data_to_send_panel_reverse[] = {
0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
@@ -300,42 +386,49 @@ static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1, 0xf6, 0xf6, 0xc1
};
- if (lcd->dsim_dev->panel_reverse)
+ if (lcd->dsim_dev->panel_reverse) {
+ pr_err("Panel Reverse Called\n");
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send_panel_reverse,
ARRAY_SIZE(data_to_send_panel_reverse));
- else
- ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
- data_to_send, ARRAY_SIZE(data_to_send));
+ } else {
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE, data_to_send,
+ ARRAY_SIZE(data_to_send));
+ }
}
-static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
+static void s6e8aa0_display_cond(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xf2, 0x80, 0x03, 0x0d
+ 0xF2,
+ 0x80, 0x03, 0x0D
};
+ pr_err("func: %s, line: %d\n", __func__, __LINE__);
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
/* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
-static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
+static void s6e8aa0_gamma_cond(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
unsigned int gamma = lcd->bd->props.brightness;
+ gamma = 15;
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
- s6e8ax0_22_gamma_table[gamma],
+ s6e8aa0_22_gamma_table[gamma],
GAMMA_TABLE_COUNT);
}
-static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
+static void s6e8aa0_gamma_update(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xf7, 0x03
+ 0xF7,
+ 0x03, 0x00, 0x00
};
ops->cmd_write(lcd_to_master(lcd),
@@ -343,110 +436,67 @@ static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
+static void s6e8aa0_etc_cond1(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
- 0x0d, 0x00, 0x00
+ 0xF6,
+ 0x00, 0x02, 0x00
};
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
+static void s6e8aa0_etc_cond2(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
- 0x00
+ 0xB6,
+ 0x0C, 0x02, 0x03, 0x32, 0xC0, 0x44, 0x44, 0xC0, 0x00
};
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
+static void s6e8aa0_etc_cond3(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
+ 0xF4,
+ 0xCF, 0x0A, 0x15, 0x10, 0x19, 0x33, 0x02
};
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
+static void s6e8aa0_elvss_set(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
+ 0xB1, 0x04, 0x00
};
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
+static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
+ 0xD9,
+ 0x14, 0x40, 0x0C, 0xCB, 0xCE, 0x6E, 0xC4, 0x07, 0x40, 0x41,
+ 0xC1, 0x00, 0x60, 0x19
};
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- static const unsigned char data_to_send[] = {
- 0xe3, 0x40
- };
-
- ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_SHORT_WRITE_PARAM,
- data_to_send, ARRAY_SIZE(data_to_send));
-}
-static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- static const unsigned char data_to_send[] = {
- 0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
- };
-
- ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
- data_to_send, ARRAY_SIZE(data_to_send));
-}
-
-static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- static const unsigned char data_to_send[] = {
- 0xb1, 0x04, 0x00
- };
-
- ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
- data_to_send, ARRAY_SIZE(data_to_send));
-}
-
-static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- static const unsigned char data_to_send[] = {
- 0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
- 0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
- 0x64, 0xaf
- };
-
- ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
- data_to_send, ARRAY_SIZE(data_to_send));
-}
-
-static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
+static void s6e8aa0_sleep_in(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
@@ -458,7 +508,7 @@ static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
+static void s6e8aa0_sleep_out(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
@@ -470,7 +520,7 @@ static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
+static void s6e8aa0_display_on(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
@@ -482,7 +532,7 @@ static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
+static void s6e8aa0_display_off(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
@@ -494,116 +544,21 @@ static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
+static void s6e8aa0_apply_level2_key(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
static const unsigned char data_to_send[] = {
- 0xf0, 0x5a, 0x5a
+ 0xfc, 0x5a, 0x5a
};
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
data_to_send, ARRAY_SIZE(data_to_send));
}
-static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- static const unsigned char data_to_send[] = {
- 0xc0, 0x01
- };
-
- ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_SHORT_WRITE,
- data_to_send, ARRAY_SIZE(data_to_send));
-}
-
-static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- static const unsigned char data_to_send[] = {
- 0xc0, 0x00
- };
-
- ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_SHORT_WRITE,
- data_to_send, ARRAY_SIZE(data_to_send));
-}
-
-/* Full white 50% reducing setting */
-static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
-{
- struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- /* Full white 50% reducing setting */
- static const unsigned char cutoff_50[] = {
- 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
- 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
- 0x3f, 0x46
- };
- /* Full white 45% reducing setting */
- static const unsigned char cutoff_45[] = {
- 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
- 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
- 0x37, 0x3d
- };
- /* Full white 40% reducing setting */
- static const unsigned char cutoff_40[] = {
- 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
- 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
- 0x31, 0x36
- };
-
- if (lcd->acl_enable) {
- if (lcd->cur_acl == 0) {
- if (lcd->gamma == 0 || lcd->gamma == 1) {
- s6e8ax0_acl_off(lcd);
- dev_dbg(&lcd->ld->dev,
- "cur_acl=%d\n", lcd->cur_acl);
- } else
- s6e8ax0_acl_on(lcd);
- }
- switch (lcd->gamma) {
- case 0: /* 30cd */
- s6e8ax0_acl_off(lcd);
- lcd->cur_acl = 0;
- break;
- case 1 ... 3: /* 50cd ~ 90cd */
- ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_LONG_WRITE,
- cutoff_40,
- ARRAY_SIZE(cutoff_40));
- lcd->cur_acl = 40;
- break;
- case 4 ... 7: /* 120cd ~ 210cd */
- ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_LONG_WRITE,
- cutoff_45,
- ARRAY_SIZE(cutoff_45));
- lcd->cur_acl = 45;
- break;
- case 8 ... 10: /* 220cd ~ 300cd */
- ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_LONG_WRITE,
- cutoff_50,
- ARRAY_SIZE(cutoff_50));
- lcd->cur_acl = 50;
- break;
- default:
- break;
- }
- } else {
- s6e8ax0_acl_off(lcd);
- lcd->cur_acl = 0;
- dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
- }
-}
-
-static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
+static void s6e8aa0_read_id(struct s6e8aa0 *lcd, u8 *mtp_id)
{
unsigned int ret;
- unsigned int addr = 0xd1; /* MTP ID */
+ unsigned int addr = 0xD1; /* MTP ID */
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
ret = ops->cmd_read(lcd_to_master(lcd),
@@ -611,61 +566,52 @@ static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
addr, 3, mtp_id);
}
-static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
+static int s6e8aa0_panel_init(struct s6e8aa0 *lcd)
{
- s6e8ax0_apply_level2_key(lcd);
- s6e8ax0_sleep_out(lcd);
- msleep(1);
- s6e8ax0_panel_cond(lcd);
- s6e8ax0_display_cond(lcd);
- s6e8ax0_gamma_cond(lcd);
- s6e8ax0_gamma_update(lcd);
-
- s6e8ax0_etc_cond1(lcd);
- s6e8ax0_etc_cond2(lcd);
- s6e8ax0_etc_cond3(lcd);
- s6e8ax0_etc_cond4(lcd);
- s6e8ax0_etc_cond5(lcd);
- s6e8ax0_etc_cond6(lcd);
- s6e8ax0_etc_cond7(lcd);
+ s6e8aa0_apply_level2_key(lcd);
+ mdelay(16);
+ s6e8aa0_sleep_out(lcd);
+ mdelay(5);
+ s6e8aa0_panel_cond(lcd);
+ s6e8aa0_display_cond(lcd);
+ s6e8aa0_gamma_cond(lcd);
+ s6e8aa0_gamma_update(lcd);
- s6e8ax0_elvss_nvm_set(lcd);
- s6e8ax0_elvss_set(lcd);
+ s6e8aa0_etc_cond1(lcd);
+ s6e8aa0_etc_cond2(lcd);
+ s6e8aa0_etc_cond3(lcd);
- s6e8ax0_acl_ctrl_set(lcd);
- s6e8ax0_acl_on(lcd);
-
- /* if ID3 value is not 33h, branch private elvss mode */
- msleep(lcd->ddi_pd->power_on_delay);
+ s6e8aa0_elvss_nvm_set(lcd);
+ s6e8aa0_elvss_set(lcd);
+ mdelay(120);
return 0;
}
-static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
+static int s6e8aa0_update_gamma_ctrl(struct s6e8aa0 *lcd, int brightness)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
- s6e8ax0_22_gamma_table[brightness],
- ARRAY_SIZE(s6e8ax0_22_gamma_table));
+ s6e8aa0_22_gamma_table[brightness],
+ ARRAY_SIZE(s6e8aa0_22_gamma_table));
/* update gamma table. */
- s6e8ax0_gamma_update(lcd);
+ s6e8aa0_gamma_update(lcd);
lcd->gamma = brightness;
return 0;
}
-static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
+static int s6e8aa0_gamma_ctrl(struct s6e8aa0 *lcd, int gamma)
{
- s6e8ax0_update_gamma_ctrl(lcd, gamma);
-
+ s6e8aa0_update_gamma_ctrl(lcd, gamma);
return 0;
}
-static int s6e8ax0_set_power(struct lcd_device *ld, int power)
+static int s6e8aa0_set_power(struct lcd_device *ld, int power)
{
- struct s6e8ax0 *lcd = lcd_get_data(ld);
+ struct s6e8aa0 *lcd = lcd_get_data(ld);
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
int ret = 0;
@@ -697,22 +643,22 @@ static int s6e8ax0_set_power(struct lcd_device *ld, int power)
return ret;
}
-static int s6e8ax0_get_power(struct lcd_device *ld)
+static int s6e8aa0_get_power(struct lcd_device *ld)
{
- struct s6e8ax0 *lcd = lcd_get_data(ld);
+ struct s6e8aa0 *lcd = lcd_get_data(ld);
return lcd->power;
}
-static int s6e8ax0_get_brightness(struct backlight_device *bd)
+static int s6e8aa0_get_brightness(struct backlight_device *bd)
{
return bd->props.brightness;
}
-static int s6e8ax0_set_brightness(struct backlight_device *bd)
+static int s6e8aa0_set_brightness(struct backlight_device *bd)
{
int ret = 0, brightness = bd->props.brightness;
- struct s6e8ax0 *lcd = bl_get_data(bd);
+ struct s6e8aa0 *lcd = bl_get_data(bd);
if (brightness < MIN_BRIGHTNESS ||
brightness > bd->props.max_brightness) {
@@ -721,7 +667,7 @@ static int s6e8ax0_set_brightness(struct backlight_device *bd)
return -EINVAL;
}
- ret = s6e8ax0_gamma_ctrl(lcd, brightness);
+ ret = s6e8aa0_gamma_ctrl(lcd, brightness);
if (ret) {
dev_err(&bd->dev, "lcd brightness setting failed.\n");
return -EIO;
@@ -730,174 +676,267 @@ static int s6e8ax0_set_brightness(struct backlight_device *bd)
return ret;
}
-static struct lcd_ops s6e8ax0_lcd_ops = {
- .set_power = s6e8ax0_set_power,
- .get_power = s6e8ax0_get_power,
+static struct lcd_ops s6e8aa0_lcd_ops = {
+ .set_power = s6e8aa0_set_power,
+ .get_power = s6e8aa0_get_power,
};
-static const struct backlight_ops s6e8ax0_backlight_ops = {
- .get_brightness = s6e8ax0_get_brightness,
- .update_status = s6e8ax0_set_brightness,
+static const struct backlight_ops s6e8aa0_backlight_ops = {
+ .get_brightness = s6e8aa0_get_brightness,
+ .update_status = s6e8aa0_set_brightness,
};
-static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
+static void s6e8aa0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
{
- struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
msleep(lcd->ddi_pd->power_on_delay);
+ if (power) {
+ gpio_request_one(lcd->gpio_reset, GPIOF_OUT_INIT_HIGH, 0);
+ mdelay(500);
+ gpio_set_value(lcd->gpio_reset, 0);
+ mdelay(500);
+ gpio_set_value(lcd->gpio_reset, 1);
+ gpio_free(lcd->gpio_reset);
+ mdelay(5);
+
+ gpio_request_one(lcd->gpio_power, GPIOF_OUT_INIT_HIGH, 0);
+ gpio_set_value(lcd->gpio_power, 1);
+ gpio_free(lcd->gpio_power);
+
+ gpio_request_one(lcd->gpio_bl, GPIOF_OUT_INIT_HIGH, 0);
+ gpio_set_value(lcd->gpio_bl, 1);
+ gpio_free(lcd->gpio_bl);
+
+ } else {
+ gpio_request_one(lcd->gpio_reset, GPIOF_OUT_INIT_LOW, 0);
+ mdelay(500);
+ gpio_free(lcd->gpio_reset);
+
+ gpio_request_one(lcd->gpio_power, GPIOF_OUT_INIT_LOW, 0);
+ mdelay(500);
+ gpio_free(lcd->gpio_power);
+ }
+
+ mdelay(500);
+
/* lcd power on */
if (power)
- s6e8ax0_regulator_enable(lcd);
+ s6e8aa0_regulator_enable(lcd);
else
- s6e8ax0_regulator_disable(lcd);
+ s6e8aa0_regulator_disable(lcd);
msleep(lcd->ddi_pd->reset_delay);
/* lcd reset */
if (lcd->ddi_pd->reset)
lcd->ddi_pd->reset(lcd->ld);
- msleep(5);
}
-static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+static void s6e8aa0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
{
- struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ u8 mtp_id[3] = {0, };
- s6e8ax0_panel_init(lcd);
- s6e8ax0_display_on(lcd);
+ s6e8aa0_read_id(lcd, mtp_id);
+ if (mtp_id[0] == 0x00)
+ dev_err(lcd->dev, "read id failed\n");
+
+ dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
+ mtp_id[0], mtp_id[1], mtp_id[2]);
+
+ if (mtp_id[2] == 0x33)
+ dev_info(lcd->dev,
+ "ID-3 is 0xff does not support dynamic elvss\n");
+ else
+ dev_info(lcd->dev,
+ "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
+
+ s6e8aa0_panel_init(lcd);
+ s6e8aa0_display_on(lcd);
lcd->power = FB_BLANK_UNBLANK;
}
-static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
+static int s6e8aa0_update_platform_lcd_data(
+ struct s6e8aa0 *lcd_s6e8aa0)
{
- struct s6e8ax0 *lcd;
+ struct lcd_platform_data *ddi_pd = lcd_s6e8aa0->ddi_pd;
+ struct device_node *np = (struct device_node *)
+ lcd_s6e8aa0->ddi_pd->pdata;
+
+ lcd_s6e8aa0->gpio_reset = of_get_named_gpio(np, "gpio-reset", 0);
+ if (!gpio_is_valid(lcd_s6e8aa0->gpio_reset)) {
+ dev_err(lcd_s6e8aa0->dev,
+ "failed to get poweron gpio-reset information.\n");
+ return -EINVAL;
+ }
+
+ lcd_s6e8aa0->gpio_power = of_get_named_gpio(np, "gpio-power", 0);
+ if (!gpio_is_valid(lcd_s6e8aa0->gpio_power)) {
+ dev_err(lcd_s6e8aa0->dev,
+ "failed to get poweron gpio-power information.\n");
+ return -EINVAL;
+ }
+
+ lcd_s6e8aa0->gpio_bl = of_get_named_gpio(np, "gpio-bl", 0);
+ if (!gpio_is_valid(lcd_s6e8aa0->gpio_bl)) {
+ dev_err(lcd_s6e8aa0->dev,
+ "failed to get pwm-bl information.\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "enabled",
+ (unsigned int *)&ddi_pd->lcd_enabled))
+ ddi_pd->lcd_enabled = 0;
+
+ if (of_property_read_u32(np, "reset-delay",
+ &ddi_pd->reset_delay)) {
+ dev_err(lcd_s6e8aa0->dev, "reset-delay property not found");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "power-on-delay",
+ &ddi_pd->power_on_delay)) {
+ dev_err(lcd_s6e8aa0->dev, "power-on-delay property not found");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "power-off-delay",
+ &ddi_pd->power_off_delay)) {
+ dev_err(lcd_s6e8aa0->dev,
+ "power-off-delay property not found");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+
+static int s6e8aa0_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *lcd;
int ret;
- u8 mtp_id[3] = {0, };
- lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct s6e8ax0), GFP_KERNEL);
+ lcd = kzalloc(sizeof(struct s6e8aa0), GFP_KERNEL);
if (!lcd) {
- dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
+ dev_err(&dsim_dev->dev, "failed to allocate s6e8aa0 structure.\n");
return -ENOMEM;
}
+ lcd_global = lcd;
+
lcd->dsim_dev = dsim_dev;
lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
lcd->dev = &dsim_dev->dev;
+ /* get platform data information, if lcd device node is present */
+ if (lcd->ddi_pd->pdata)
+ if (s6e8aa0_update_platform_lcd_data(lcd))
+ return -EINVAL;
+
mutex_init(&lcd->lock);
- ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
+ ret = regulator_bulk_get(dsim_dev->master->dev,
+ ARRAY_SIZE(supplies), supplies);
if (ret) {
dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
- return ret;
+ goto err_lcd_register;
}
- lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
- &s6e8ax0_lcd_ops);
+ lcd->ld = lcd_device_register("s6e8aa0", lcd->dev, lcd,
+ &s6e8aa0_lcd_ops);
if (IS_ERR(lcd->ld)) {
dev_err(lcd->dev, "failed to register lcd ops.\n");
- return PTR_ERR(lcd->ld);
+ ret = PTR_ERR(lcd->ld);
+ goto err_lcd_register;
}
- lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd,
- &s6e8ax0_backlight_ops, NULL);
+ lcd->bd = backlight_device_register("s6e8aa0-bl", lcd->dev, lcd,
+ &s6e8aa0_backlight_ops, NULL);
if (IS_ERR(lcd->bd)) {
dev_err(lcd->dev, "failed to register backlight ops.\n");
ret = PTR_ERR(lcd->bd);
goto err_backlight_register;
}
-
lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
lcd->bd->props.brightness = MAX_BRIGHTNESS;
- s6e8ax0_read_id(lcd, mtp_id);
- if (mtp_id[0] == 0x00)
- dev_err(lcd->dev, "read id failed\n");
-
- dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
- mtp_id[0], mtp_id[1], mtp_id[2]);
-
- if (mtp_id[2] == 0x33)
- dev_info(lcd->dev,
- "ID-3 is 0xff does not support dynamic elvss\n");
- else
- dev_info(lcd->dev,
- "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
-
- lcd->acl_enable = 1;
- lcd->cur_acl = 0;
-
dev_set_drvdata(&dsim_dev->dev, lcd);
- dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
+ dev_dbg(lcd->dev, "probed s6e8aa0 panel driver.\n");
return 0;
err_backlight_register:
lcd_device_unregister(lcd->ld);
+
+err_lcd_register:
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+ kfree(lcd);
+
return ret;
}
#ifdef CONFIG_PM
-static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+static int s6e8aa0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
{
- struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
- s6e8ax0_sleep_in(lcd);
+ s6e8aa0_sleep_in(lcd);
msleep(lcd->ddi_pd->power_off_delay);
- s6e8ax0_display_off(lcd);
+ s6e8aa0_display_off(lcd);
- s6e8ax0_regulator_disable(lcd);
+ s6e8aa0_regulator_disable(lcd);
return 0;
}
-static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+static int s6e8aa0_resume(struct mipi_dsim_lcd_device *dsim_dev)
{
- struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
- s6e8ax0_sleep_out(lcd);
+ s6e8aa0_sleep_out(lcd);
msleep(lcd->ddi_pd->power_on_delay);
- s6e8ax0_regulator_enable(lcd);
- s6e8ax0_set_sequence(dsim_dev);
+ s6e8aa0_regulator_enable(lcd);
+ s6e8aa0_set_sequence(dsim_dev);
return 0;
}
#else
-#define s6e8ax0_suspend NULL
-#define s6e8ax0_resume NULL
+#define s6e8aa0_suspend NULL
+#define s6e8aa0_resume NULL
#endif
-static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
+static struct mipi_dsim_lcd_driver s6e8aa0_dsim_ddi_driver = {
.name = "s6e8ax0",
.id = -1,
- .power_on = s6e8ax0_power_on,
- .set_sequence = s6e8ax0_set_sequence,
- .probe = s6e8ax0_probe,
- .suspend = s6e8ax0_suspend,
- .resume = s6e8ax0_resume,
+ .power_on = s6e8aa0_power_on,
+ .set_sequence = s6e8aa0_set_sequence,
+ .probe = s6e8aa0_probe,
+ .suspend = s6e8aa0_suspend,
+ .resume = s6e8aa0_resume,
};
-static int s6e8ax0_init(void)
+static int s6e8aa0_init(void)
{
- exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
+ exynos_mipi_dsi_register_lcd_driver(&s6e8aa0_dsim_ddi_driver);
return 0;
}
-static void s6e8ax0_exit(void)
+static void s6e8aa0_exit(void)
{
return;
}
-module_init(s6e8ax0_init);
-module_exit(s6e8ax0_exit);
+module_init(s6e8aa0_init);
+module_exit(s6e8aa0_exit);
-MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
+MODULE_AUTHOR("Shaik Ameer Basha <shaik.ameer@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver");
MODULE_LICENSE("GPL");
diff --git a/firmware/edid-1920x1080.fw b/firmware/edid-1920x1080.fw
new file mode 100644
index 000000000000..e90256c4fd2c
--- /dev/null
+++ b/firmware/edid-1920x1080.fw
Binary files differ
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 22c7052e9372..b62c76703532 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -8,6 +8,7 @@
extern const char linux_banner[];
extern const char linux_proc_banner[];
+extern const char linux_scm_version_banner[];
static inline int printk_get_level(const char *buffer)
{
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index adae88f5b0ab..ebf28027b53a 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -253,7 +253,7 @@ size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
* Maximum number of entries that will be allocated in one piece, if
* a list larger than this is required then chaining will be utilized.
*/
-#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist))
+#define SG_MAX_SINGLE_ALLOC ((PAGE_SIZE<<4) / sizeof(struct scatterlist))
/*
* sg page iterator
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index e90a88a8708f..f81a7e9000e4 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -138,8 +138,10 @@ enum v4l2_colorfx {
#define V4L2_CID_ALPHA_COMPONENT (V4L2_CID_BASE+41)
#define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42)
+#define V4L2_CID_CODEC_FRAME_TAG (V4L2_CID_BASE+43)
+
/* last CID + 1 */
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+43)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44)
/* USER-class private control IDs */
diff --git a/include/video/exynos_mipi_dsim.h b/include/video/exynos_mipi_dsim.h
index 89dc88a171af..96b31a4f691f 100644
--- a/include/video/exynos_mipi_dsim.h
+++ b/include/video/exynos_mipi_dsim.h
@@ -15,7 +15,7 @@
#ifndef _EXYNOS_MIPI_DSIM_H
#define _EXYNOS_MIPI_DSIM_H
-#include <linux/device.h>
+#include <linux/platform_device.h>
#include <linux/fb.h>
#define PANEL_NAME_SIZE (32)
@@ -229,6 +229,7 @@ struct mipi_dsim_device {
struct mipi_dsim_master_ops *master_ops;
struct mipi_dsim_lcd_device *dsim_lcd_dev;
struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+ struct mipi_dsim_phy_config *dsim_phy_config;
unsigned int state;
unsigned int data_lane;
@@ -294,6 +295,32 @@ struct mipi_dsim_master_ops {
};
/*
+ * phy node structure for mipi-dsim.
+ *
+ * @reg_enable_dphy : base address to memory mapped D-PHY enable register
+ * @ctrl_bit_enable : control bit for enabling D-PHY
+ * @reg_reset_dphy : base address to memory mapped D-PHY reset register
+ * @ctrl_bit_reset : control bit for resetting D-PHY
+ */
+struct mipi_dsim_phy_config_type1 {
+ void __iomem *reg_enable_dphy;
+ int ctrlbit_enable_dphy;
+ void __iomem *reg_reset_dsim;
+ int ctrlbit_reset_dsim;
+};
+
+enum mipi_dsim_phy_config_type {
+ MIPI_DSIM_PHY_CONFIG_TYPE1,
+};
+
+struct mipi_dsim_phy_config {
+ enum mipi_dsim_phy_config_type type;
+ union {
+ struct mipi_dsim_phy_config_type1 phy_cfg_type1;
+ };
+};
+
+/*
* device structure for mipi-dsi based lcd panel.
*
* @name: name of the device to use with this device, or an
diff --git a/init/main.c b/init/main.c
index d03d2ec2eacf..aa84693fa67b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -499,6 +499,7 @@ asmlinkage void __init start_kernel(void)
boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
+ pr_notice("%s", linux_scm_version_banner);
setup_arch(&command_line);
mm_init_owner(&init_mm, &init_task);
mm_init_cpumask(&init_mm);
diff --git a/init/version.c b/init/version.c
index 1a4718e500fe..3978f0298c98 100644
--- a/init/version.c
+++ b/init/version.c
@@ -48,3 +48,6 @@ const char linux_proc_banner[] =
"%s version %s"
" (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
" (" LINUX_COMPILER ") %s\n";
+
+const char linux_scm_version_banner [] =
+ "Kernel was built at commit id '" KERNEL_GIT_ID "'\n";
diff --git a/linaro/configs/arndale.conf b/linaro/configs/arndale.conf
index f4b022498b15..279f3c71469a 100644
--- a/linaro/configs/arndale.conf
+++ b/linaro/configs/arndale.conf
@@ -18,11 +18,15 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_PM_RUNTIME=y
+CONFIG_EXTRA_FIRMWARE="edid-1920x1080.fw"
+CONFIG_CMA=y
+CONFIG_CMA_SIZE_MBYTES=128
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
CONFIG_ATA=y
CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_SATA_EXYNOS=y
CONFIG_AX88796=y
CONFIG_AX88796_93CX6=y
CONFIG_USB_USBNET=y
@@ -44,9 +48,32 @@ CONFIG_MFD_SEC_CORE=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_S5M8767=y
+CONFIG_DRM=y
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_DRM_EXYNOS=y
+CONFIG_DRM_EXYNOS_DMABUF=y
+CONFIG_DRM_EXYNOS_HDMI=y
+CONFIG_DRM_EXYNOS_FIMD=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_EXYNOS_VIDEO=y
+CONFIG_EXYNOS_MIPI_DSI=y
+CONFIG_EXYNOS_LCD_S6E8AX0=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SAMSUNG=y
+CONFIG_SND_SOC_SMDK_I2S_STUB=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_HOST=y
CONFIG_USB_PHY=y
CONFIG_SAMSUNG_USB2PHY=y
CONFIG_SAMSUNG_USB3PHY=y
@@ -65,6 +92,10 @@ CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_IDMAC=y
CONFIG_MMC_DW_EXYNOS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_S3C=y
+CONFIG_PWM=y
+CONFIG_PWM_SAMSUNG=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_RT_MUTEXES=y
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index badb6fbacaa6..58784ca32d90 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -246,6 +246,9 @@ config SND_SOC_CX20442
tristate
depends on TTY
+config SND_SOC_I2S_STUB
+ tristate
+
config SND_SOC_JZ4740_CODEC
select REGMAP_MMIO
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 70fd8066f546..7b7d3d032583 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -29,6 +29,7 @@ snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-dmic-objs := dmic.o
+snd-soc-i2s-stub-objs := i2s_stub.o
snd-soc-isabelle-objs := isabelle.o
snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o
@@ -158,6 +159,7 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_I2S_STUB) += snd-soc-i2s-stub.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
diff --git a/sound/soc/codecs/i2s_stub.c b/sound/soc/codecs/i2s_stub.c
new file mode 100644
index 000000000000..df6b08944ed3
--- /dev/null
+++ b/sound/soc/codecs/i2s_stub.c
@@ -0,0 +1,74 @@
+/*
+ * ALSA SoC I2S Stub Codec driver
+ *
+ * This driver is used by controllers which can operate in I2S mode with
+ * Stub codec driver for I2S mode.
+ *
+ * The code is based on sound/soc/codec/spdif_transceiver.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+
+#define I2S_STUB_RATES SNDRV_PCM_RATE_8000_192000
+#define I2S_STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+
+static struct snd_soc_codec_driver soc_codec_i2s_stub;
+
+static struct snd_soc_dai_driver i2s_stub_dai = {
+ .name = "i2s-stub-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = I2S_STUB_RATES,
+ .formats = I2S_STUB_FORMATS,
+ },
+};
+
+static int i2s_stub_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_i2s_stub,
+ &i2s_stub_dai, 1);
+}
+
+static int i2s_stub_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id i2s_stub_dt_ids[] = {
+ { .compatible = "linux,i2s-stub", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, i2s_stub_dt_ids);
+#endif
+
+static struct platform_driver i2s_stub_driver = {
+ .probe = i2s_stub_probe,
+ .remove = i2s_stub_remove,
+ .driver = {
+ .name = "i2s-stub",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(i2s_stub_dt_ids),
+ },
+};
+
+module_platform_driver(i2s_stub_driver);
+
+MODULE_AUTHOR("Tushar Behera");
+MODULE_DESCRIPTION("I2S stub codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform: i2s-stub");
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 9855dfc3e3ec..a3b992dd88d2 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -222,3 +222,12 @@ config SND_SOC_LITTLEMILL
select SND_SAMSUNG_I2S
select MFD_WM8994
select SND_SOC_WM8994
+
+config SND_SOC_SMDK_I2S_STUB
+ tristate "SoC I2S Audio support for boards without external codec chip"
+ depends on SND_SOC_SAMSUNG
+ select SND_SAMSUNG_I2S
+ select SND_SOC_I2S_STUB
+ help
+ Say Y if you want to add support for SoC audio on boards without
+ exteral codec chip.
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 709f6059ad67..d2253219b4db 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -43,6 +43,7 @@ snd-soc-tobermory-objs := tobermory.o
snd-soc-lowland-objs := lowland.o
snd-soc-littlemill-objs := littlemill.o
snd-soc-bells-objs := bells.o
+snd-soc-smdk-i2s-stub-objs := smdk_i2s_stub.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -67,3 +68,4 @@ obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
+obj-$(CONFIG_SND_SOC_SMDK_I2S_STUB) += snd-soc-smdk-i2s-stub.o
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 21b79262010e..ddea134aff25 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -76,7 +76,8 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
pr_debug("Entered %s\n", __func__);
- limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+ limit = (unsigned int) (prtd->dma_end - prtd->dma_start)
+ / prtd->dma_period;
pr_debug("%s: loaded %d, limit %d\n",
__func__, prtd->dma_loaded, limit);
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index ce1e1e16f250..6bc658a80b3b 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -282,7 +282,7 @@ static irqreturn_t iis_irq(int irqno, void *dev_id)
addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
addr += prtd->periodsz;
- addr %= (prtd->end - prtd->start);
+ addr %= (unsigned int) (prtd->end - prtd->start);
addr += idma.lp_tx_addr;
writel(addr, idma.regs + I2SLVL0ADDR);
diff --git a/sound/soc/samsung/smdk_i2s_stub.c b/sound/soc/samsung/smdk_i2s_stub.c
new file mode 100644
index 000000000000..b20c8da308a8
--- /dev/null
+++ b/sound/soc/samsung/smdk_i2s_stub.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2011 Insignal Co., Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "i2s.h"
+
+static int set_epll_rate(unsigned long rate)
+{
+ struct clk *fout_epll;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+ return -ENOENT;
+ }
+
+ if (rate == clk_get_rate(fout_epll))
+ goto out;
+
+ clk_set_rate(fout_epll, rate);
+out:
+ clk_put(fout_epll);
+
+ return 0;
+}
+
+static int smdk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int bfs, psr, rfs, ret;
+ unsigned long rclk;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U24:
+ case SNDRV_PCM_FORMAT_S24:
+ bfs = 48;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ rfs = (bfs == 48) ? 384 : 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ case 12000:
+ rfs = (bfs == 48) ? 768 : 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rclk = params_rate(params) * rfs;
+
+ switch (rclk) {
+ case 4096000:
+ case 5644800:
+ case 6144000:
+ case 8467200:
+ case 9216000:
+ psr = 8;
+ break;
+ case 8192000:
+ case 11289600:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ psr = 4;
+ break;
+ case 22579200:
+ case 24576000:
+ case 33868800:
+ case 36864000:
+ psr = 2;
+ break;
+ case 67737600:
+ case 73728000:
+ psr = 1;
+ break;
+ default:
+ printk(KERN_ERR "Not yet supported!\n");
+ return -EINVAL;
+ }
+
+ set_epll_rate(rclk * psr);
+
+ /* Set the AP DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, rfs,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops smdk_ops = {
+ .hw_params = smdk_hw_params,
+};
+
+static int smdk_init_paiftx(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link smdk_dai[] = {
+ { /* Primary DAI i/f */
+ .name = "I2S",
+ .stream_name = "Pri_Dai",
+ .cpu_dai_name = "samsung-i2s.0",
+ .codec_dai_name = "i2s-stub-hifi",
+ .platform_name = "samsung-i2s.0",
+ .codec_name = "i2s-stub",
+ .init = smdk_init_paiftx,
+ .ops = &smdk_ops,
+ },
+};
+
+static struct snd_soc_card smdk = {
+ .name = "I2S-STUB",
+ .owner = THIS_MODULE,
+ .dai_link = smdk_dai,
+ .num_links = ARRAY_SIZE(smdk_dai),
+};
+
+static int smdk_audio_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &smdk;
+ struct snd_soc_dai_link *dai_link = &smdk_dai[0];
+
+ card->dev = &pdev->dev;
+
+ if (np) {
+ dai_link->cpu_of_node = of_parse_phandle(np,
+ "samsung,i2s-controller", 0);
+ if (!dai_link->cpu_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'samsung,i2s-controller' missing\n");
+ return -EINVAL;
+ }
+
+ dai_link->cpu_dai_name = NULL;
+ dai_link->platform_name = NULL;
+ dai_link->platform_of_node = dai_link->cpu_of_node;
+
+ dai_link->codec_of_node = of_parse_phandle(np,
+ "samsung,audio-codec", 0);
+ if (!dai_link->codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'samsung,audio-codec' missing\n");
+ return -EINVAL;
+ }
+ dai_link->codec_name = NULL;
+ }
+
+ ret = snd_soc_register_card(card);
+
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+ return ret;
+}
+
+static int smdk_audio_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_i2s_stub_of_match[] = {
+ { .compatible = "samsung,smdk-i2s-stub", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
+#endif /* CONFIG_OF */
+
+static struct platform_driver smdk_audio_driver = {
+ .driver = {
+ .name = "smdk-i2s-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(samsung_i2s_stub_of_match),
+ },
+ .probe = smdk_audio_probe,
+ .remove = smdk_audio_remove,
+};
+
+module_platform_driver(smdk_audio_driver);
+
+MODULE_AUTHOR("Tushar Behera");
+MODULE_DESCRIPTION("ALSA SoC I2S STUB");
+MODULE_LICENSE("GPL");