aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Konovalov <andrey.konovalov@linaro.org>2013-06-25 23:09:56 +0400
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-06-25 23:09:56 +0400
commitc125eedc037419ae7a90c1a3f10fa0099d87d392 (patch)
treedd4e2440b936a67fea0db0dc43db195a26b7f46f
parent7c00ac223e7e705a57b871c5fab3eadf10d1b2ff (diff)
parent86c08fa921a5839399bd13d23c535fde2e086c5a (diff)
Merge branch 'tracking-arndale-rt' into merge-linaro-no-preempt-rt
-rw-r--r--Documentation/devicetree/bindings/usb/exynos-usb.txt41
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/arm/boot/dts/Makefile1
-rw-r--r--arch/arm/boot/dts/exynos5250-arndale.dts403
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts12
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi33
-rw-r--r--arch/arm/mach-exynos/Kconfig2
-rw-r--r--arch/arm/mach-exynos/clock-exynos5.c27
-rw-r--r--arch/arm/mach-exynos/common.c5
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h9
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-pmu.h4
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-usb-phy.h86
-rw-r--r--arch/arm/mach-exynos/mach-exynos5-dt.c33
-rw-r--r--arch/arm/mach-exynos/mct.c8
-rw-r--r--arch/arm/mach-exynos/setup-usb-phy.c189
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/usb-phy.h8
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c51
-rw-r--r--drivers/mfd/sec-core.c77
-rw-r--r--drivers/net/usb/asix_devices.c32
-rw-r--r--drivers/regulator/s5m8767.c196
-rw-r--r--drivers/thermal/exynos_thermal.c108
-rw-r--r--drivers/thermal/step_wise.c19
-rw-r--r--drivers/tty/serial/samsung.c5
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/core/hub.c35
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/dwc3/core.c8
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c9
-rw-r--r--drivers/usb/host/ehci-s5p.c101
-rw-r--r--drivers/usb/host/ohci-exynos.c77
-rw-r--r--drivers/usb/host/xhci-plat.c1
-rw-r--r--drivers/usb/host/xhci.c2
-rw-r--r--drivers/usb/otg/otg.c3
-rw-r--r--drivers/usb/phy/Kconfig7
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/samsung-usbphy.c1004
-rw-r--r--include/linux/mfd/samsung/core.h3
-rw-r--r--include/linux/platform_data/exynos_thermal.h3
-rw-r--r--include/linux/platform_data/samsung-usbphy.h29
-rw-r--r--include/linux/thermal.h2
-rw-r--r--include/linux/usb/samsung_usb_phy.h29
43 files changed, 2493 insertions, 179 deletions
diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt
new file mode 100644
index 000000000000..45dadca510fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt
@@ -0,0 +1,41 @@
+Samsung Exynos SoC USB controller
+
+The device node for USB controller for Samsung SOC have
+following properties
+
+OHCI
+Required properties:
+ - compatible: should be "samsung,exynos-ohci" for USB 2.0
+ OHCI companion controller in host mode.
+ - reg: physical base address of the controller and length
+ of memory mapped.
+ - interrupts: interrupt number to the cpu.
+
+ohci {
+ compatible = "samsung,exynos-ohci";
+ reg = <0x12120000 0x100>;
+ interrupts = <0 71 0>;
+};
+
+EHCI
+Required properties:
+ - compatible: should be "samsung,exynos-ehci" for USB 2.0
+ EHCI controller in host mode.
+ - reg: physical base address of the controller and length
+ of memory mapped.
+ - interrupts: interrupt number to the cpu.
+
+Optional properties:
+ - samsung,vbus-gpio: if present, specifies the GPIO
+ that needs to be pulled up for the bus to be powered.
+
+ehci {
+ compatible = "samsung,exynos-ehci";
+ reg = <0x12110000 0x100>;
+ interrupts = <0 71 0>;
+};
+
+ehci {
+ samsung,vbus-gpio = <&gpx2 6 1 3 3>;
+};
+
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 986614df8c05..e5367fc574ec 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1464,6 +1464,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/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 5ebb44fe826a..60a9e5285b7e 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -44,6 +44,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
exynos4210-trats.dtb \
exynos4412-smdk4412.dtb \
exynos5250-smdk5250.dtb \
+ exynos5250-arndale.dtb \
exynos5250-snow.dtb \
exynos5440-ssdk5440.dtb
dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
new file mode 100644
index 000000000000..dc21a5cc064c
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -0,0 +1,403 @@
+/*
+ * SAMSUNG ARNDALE5250 board device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.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
+ * published by the Free Software Foundation.
+*/
+
+/dts-v1/;
+/include/ "exynos5250.dtsi"
+
+/ {
+ model = "SAMSUNG ARNDALE board based on EXYNOS5250";
+ compatible = "samsung,arndale", "samsung,exynos5250";
+
+ aliases {
+ mshc0 = &dwmmc_0;
+ mshc1 = &dwmmc_1;
+ mshc2 = &dwmmc_2;
+ mshc3 = &dwmmc_3;
+ };
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
+ };
+
+ chosen {
+ bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
+ };
+
+ i2c@12C60000 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
+ samsung,i2c-slave-addr = <0x66>;
+ gpios = <&gpb3 0 2 3 0>,
+ <&gpb3 1 2 3 0>;
+
+ s5m8767_pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+
+ s5m8767,pmic-buck2-dvs-voltage = <1300000>;
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>;
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>;
+ s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 1 0 0>, /* DVS1 */
+ <&gpd1 1 1 0 0>, /* DVS2 */
+ <&gpd1 2 1 0 0>; /* DVS3 */
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */
+ <&gpx2 4 1 0 0>, /* SET2 */
+ <&gpx2 5 1 0 0>; /* SET3 */
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE_1.0V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_28IO_DP_1.35V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "VDD_COMMON1_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "VDD_IOPERI_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "VDD_EXT_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "VDD_MPLL_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "VDD_XPLL_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "VDD_COMMON2_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "VDD_33ON_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "VDD_COMMON3_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "VDD_ABB2_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "VDD_USB_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "VDDQ_C2C_W_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "VDD18_ABB0-3_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "VDD10_COMMON4_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "VDD18_HSIC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "VDDQ_MMC2-3_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "VDD_33ON_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "VDD_MIF_1.2V";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "VDD_INT_1.0V";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "VDD_G3D_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "VDD_MEM_1.35V";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1355000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ };
+ };
+ };
+
+ i2c@12C70000 {
+ status = "disabled";
+ };
+
+ i2c@12C80000 {
+ status = "disabled";
+ };
+
+ i2c@12C90000 {
+ status = "disabled";
+ };
+
+ i2c@12CA0000 {
+ status = "disabled";
+ };
+
+ i2c@12CB0000 {
+ status = "disabled";
+ };
+
+ i2c@12CC0000 {
+ status = "disabled";
+ };
+
+ i2c@12CD0000 {
+ status = "disabled";
+ };
+
+ i2c@121D0000 {
+ status = "disabled";
+ };
+
+ dwmmc_0: dwmmc0@12200000 {
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ fifo-depth = <0x80>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+ <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+ <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+ <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+ <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+ };
+ };
+
+ dwmmc_1: dwmmc1@12210000 {
+ status = "disabled";
+ };
+
+ dwmmc_2: dwmmc2@12220000 {
+ num-slots = <1>;
+ supports-highspeed;
+ fifo-depth = <0x80>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ samsung,cd-pinmux-gpio = <&gpc3 2 2 3 3>;
+ gpios = <&gpc3 0 2 0 3>, <&gpc3 1 2 0 3>,
+ <&gpc3 3 2 3 3>, <&gpc3 4 2 3 3>,
+ <&gpc3 5 2 3 3>, <&gpc3 6 2 3 3>,
+ <&gpc4 3 3 3 3>, <&gpc4 3 3 3 3>,
+ <&gpc4 5 3 3 3>, <&gpc4 6 3 3 3>;
+ };
+ };
+
+ dwmmc_3: dwmmc3@12230000 {
+ status = "disabled";
+ };
+
+ spi_0: spi@12d20000 {
+ status = "disabled";
+ };
+
+ spi_1: spi@12d30000 {
+ status = "disabled";
+ };
+
+ spi_2: spi@12d40000 {
+ status = "disabled";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ menu {
+ label = "SW-TACT2";
+ gpios = <&gpx1 4 0 0x10000 2>;
+ linux,code = <139>;
+ gpio-key,wakeup;
+ };
+
+ home {
+ label = "SW-TACT3";
+ gpios = <&gpx1 5 0 0x10000 2>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ };
+
+ up {
+ label = "SW-TACT4";
+ gpios = <&gpx1 6 0 0x10000 2>;
+ linux,code = <103>;
+ gpio-key,wakeup;
+ };
+
+ down {
+ label = "SW-TACT5";
+ gpios = <&gpx1 7 0 0x10000 2>;
+ linux,code = <108>;
+ gpio-key,wakeup;
+ };
+
+ back {
+ label = "SW-TACT6";
+ gpios = <&gpx2 0 0 0x10000 2>;
+ linux,code = <158>;
+ gpio-key,wakeup;
+ };
+
+ wakeup {
+ label = "SW-TACT7";
+ gpios = <&gpx2 1 0 0x10000 2>;
+ linux,code = <143>;
+ gpio-key,wakeup;
+ };
+ };
+
+ ehci {
+ samsung,hub-reset = <&gpx3 5 1 0 3>;
+ samsung,hub-connect = <&gpd1 7 1 0 3>;
+ };
+};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index e05b18f3c33d..fadc5368b5d6 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -23,6 +23,14 @@
reg = <0x40000000 0x80000000>;
};
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
+ };
+
chosen {
bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
};
@@ -204,4 +212,8 @@
samsung,mfc-r = <0x43000000 0x800000>;
samsung,mfc-l = <0x51000000 0x800000>;
};
+
+ ehci {
+ samsung,vbus-gpio = <&gpx2 6 1 3 3>;
+ };
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 3acf594ea60b..1210ec384836 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -47,10 +47,15 @@
};
gic:interrupt-controller@10481000 {
- compatible = "arm,cortex-a9-gic";
+ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
#interrupt-cells = <3>;
+ #address-cells = <0>;
interrupt-controller;
- reg = <0x10481000 0x1000>, <0x10482000 0x2000>;
+ reg = <0x10481000 0x1000>,
+ <0x10482000 0x2000>,
+ <0x10484000 0x2000>,
+ <0x10486000 0x2000>;
+ interrupts = <1 9 0xf04>;
};
combiner:interrupt-controller@10440000 {
@@ -81,6 +86,29 @@
interrupts = <0 96 0>;
};
+ usbphy {
+ compatible = "samsung,exynos5250-usbphy";
+ reg = <0x12130000 0x100>, <0x12100000 0x100>;
+ };
+
+ usb@12000000 {
+ compatible = "samsung,exynos-dwc3";
+ reg = <0x12000000 0x10000>;
+ interrupts = <0 72 0>;
+ };
+
+ ohci {
+ compatible = "samsung,exynos-ohci";
+ reg = <0x12120000 0x100>;
+ interrupts = <0 71 0>;
+ };
+
+ ehci {
+ compatible = "samsung,exynos-ehci";
+ reg = <0x12110000 0x100>;
+ interrupts = <0 71 0>;
+ };
+
rtc {
compatible = "samsung,s3c6410-rtc";
reg = <0x101E0000 0x100>;
@@ -269,6 +297,7 @@
#size-cells = <0>;
};
+
amba {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 85afb031b676..795e157d4c98 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -428,6 +428,8 @@ config MACH_EXYNOS5_DT
depends on ARCH_EXYNOS5
select ARM_AMBA
select USE_OF
+ select EXYNOS4_SETUP_USB_PHY
+ select USB_ARCH_HAS_XHCI
help
Machine support for Samsung EXYNOS5 machine with device tree enabled.
Select this if a fdt blob is available for the EXYNOS5 SoC based board.
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
index e9d7b80bae49..49a20d2c05d5 100644
--- a/arch/arm/mach-exynos/clock-exynos5.c
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -747,6 +747,11 @@ static struct clk exynos5_init_clocks_off[] = {
.enable = exynos5_clk_ip_fsys_ctrl ,
.ctrlbit = (1 << 18),
}, {
+ .name = "usbdrd30",
+ .parent = &exynos5_clk_aclk_200.clk,
+ .enable = exynos5_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 19),
+ }, {
.name = "usbotg",
.enable = exynos5_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 7),
@@ -1011,6 +1016,16 @@ static struct clksrc_sources exynos5_clkset_group = {
.nr_sources = ARRAY_SIZE(exynos5_clkset_group_list),
};
+struct clk *exynos5_clkset_usbdrd30_list[] = {
+ [0] = &exynos5_clk_mout_mpll.clk,
+ [1] = &exynos5_clk_mout_cpll.clk,
+};
+
+struct clksrc_sources exynos5_clkset_usbdrd30 = {
+ .sources = exynos5_clkset_usbdrd30_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_usbdrd30_list),
+};
+
/* Possible clock sources for aclk_266_gscl_sub Mux */
static struct clk *clk_src_gscl_266_list[] = {
[0] = &clk_ext_xtal_mux,
@@ -1305,7 +1320,17 @@ static struct clksrc_clk exynos5_clksrcs[] = {
.parent = &exynos5_clk_mout_cpll.clk,
},
.reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 3 },
- },
+ }, {
+
+ .clk = {
+ .name = "sclk_usbdrd30",
+ .enable = exynos5_clksrc_mask_fsys_ctrl,
+ .ctrlbit = (1 << 28),
+ },
+ .sources = &exynos5_clkset_usbdrd30,
+ .reg_src = {.reg = EXYNOS5_CLKSRC_FSYS, .shift = 28, .size = 1},
+ .reg_div = {.reg = EXYNOS5_CLKDIV_FSYS0, .shift = 24, .size = 4},
+ }
};
/* Clock initialization code */
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 3b6de7abcfe8..b38d9d39b9b2 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -289,6 +289,11 @@ static struct map_desc exynos5440_iodesc0[] __initdata = {
.pfn = __phys_to_pfn(EXYNOS5440_PA_UART0),
.length = SZ_512K,
.type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S3C_VA_USB_HSPHY,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_USB_PHY),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
},
};
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 1df6abbf53b8..858253be187a 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -188,7 +188,7 @@
#define EXYNOS4_PA_HSOTG 0x12480000
#define EXYNOS4_PA_USB_HSPHY 0x125B0000
-
+#define EXYNOS5_PA_HSPHY 0x12130000
#define EXYNOS4_PA_SATA 0x12560000
#define EXYNOS4_PA_SATAPHY 0x125D0000
#define EXYNOS4_PA_SATAPHY_CTRL 0x126B0000
@@ -199,11 +199,16 @@
#define EXYNOS4_PA_EHCI 0x12580000
#define EXYNOS4_PA_OHCI 0x12590000
#define EXYNOS4_PA_HSPHY 0x125B0000
+#define EXYNOS5_PA_DRD 0x12000000
+#define EXYNOS5_PA_EHCI 0x12110000
+#define EXYNOS5_PA_OHCI 0x12120000
#define EXYNOS4_PA_MFC 0x13400000
#define EXYNOS4_PA_UART 0x13800000
#define EXYNOS5_PA_UART 0x12C00000
+#define EXYNOS5_PA_USB_PHY 0x12130000
+
#define EXYNOS4_PA_VP 0x12C00000
#define EXYNOS4_PA_MIXER 0x12C10000
#define EXYNOS4_PA_SDO 0x12C20000
@@ -246,7 +251,7 @@
#define S3C_PA_SPI1 EXYNOS4_PA_SPI1
#define S3C_PA_SPI2 EXYNOS4_PA_SPI2
#define S3C_PA_USB_HSOTG EXYNOS4_PA_HSOTG
-
+#define S3C_PA_USB_PHY EXYNOS4_PA_HSPHY
#define S5P_PA_EHCI EXYNOS4_PA_EHCI
#define S5P_PA_FIMC0 EXYNOS4_PA_FIMC0
#define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 3f30aa1ae354..dfc39f204d18 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -41,6 +41,10 @@
#define S5P_HDMI_PHY_CONTROL S5P_PMUREG(0x0700)
#define S5P_HDMI_PHY_ENABLE (1 << 0)
+/* only for EXYNOS5250*/
+#define S5P_USBDRD_PHY_CONTROL S5P_PMUREG(0x0704)
+#define S5P_USBDRD_PHY_ENABLE (1 << 0)
+
#define S5P_DAC_PHY_CONTROL S5P_PMUREG(0x070C)
#define S5P_DAC_PHY_ENABLE (1 << 0)
diff --git a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
index 07277735252e..2df4bd7e540a 100644
--- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
+++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
@@ -13,6 +13,7 @@
#define EXYNOS4_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY)
+/* Exynos 4 */
#define EXYNOS4_PHYPWR EXYNOS4_HSOTG_PHYREG(0x00)
#define PHY1_HSIC_NORMAL_MASK (0xf << 9)
#define PHY1_HSIC1_SLEEP (1 << 12)
@@ -71,4 +72,89 @@
#define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34)
#define FPENABLEN (1 << 0)
+/* Exynos 5 */
+#define EXYNOS5_PHY_HOST_CTRL0 EXYNOS4_HSOTG_PHYREG(0x00)
+#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
+
+#define HOST_CTRL0_REFCLKSEL_XTAL (0x0)
+#define HOST_CTRL0_REFCLKSEL_EXTL (0x1)
+#define HOST_CTRL0_REFCLKSEL_CLK_CORE (0x2)
+#define HOST_CTRL0_REFCLKSEL_MASK (0x3)
+#define HOST_CTRL0_REFCLKSEL_SHIFT (19)
+
+#define EXYNOS5_CLKSEL_50M (0x7)
+#define EXYNOS5_CLKSEL_24M (0x5)
+#define EXYNOS5_CLKSEL_20M (0x4)
+#define EXYNOS5_CLKSEL_19200K (0x3)
+#define EXYNOS5_CLKSEL_12M (0x2)
+#define EXYNOS5_CLKSEL_10M (0x1)
+#define EXYNOS5_CLKSEL_9600K (0x0)
+#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
+#define HOST_CTRL0_CLKSEL_SHIFT (16)
+
+#define HOST_CTRL0_COMMONON_N (0x1 << 9)
+#define HOST_CTRL0_SIDDQ (0x1 << 6)
+#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
+#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
+#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
+#define HOST_CTRL0_UTMISWRST (0x1 << 2)
+#define HOST_CTRL0_LINKSWRST (0x1 << 1)
+#define HOST_CTRL0_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_TUNE0 EXYNOS4_HSOTG_PHYREG(0x04)
+#define EXYNOS5_PHY_HOST_TEST0 EXYNOS4_HSOTG_PHYREG(0x08)
+
+#define EXYNOS5_PHY_HSIC_CTRL1 EXYNOS4_HSOTG_PHYREG(0x10)
+#define EXYNOS5_PHY_HSIC_CTRL2 EXYNOS4_HSOTG_PHYREG(0x20)
+#define HSIC_CTRL_REFCLKSEL (0x2)
+#define HSIC_CTRL_REFCLKSEL_MASK (0x3)
+#define HSIC_CTRL_REFCLKSEL_SHIFT (23)
+
+#define HSIC_CTRL_REFCLKDIV_12 (0x24)
+#define HSIC_CTRL_REFCLKDIV_15 (0x1C)
+#define HSIC_CTRL_REFCLKDIV_16 (0x1A)
+#define HSIC_CTRL_REFCLKDIV_19_2 (0x15)
+#define HSIC_CTRL_REFCLKDIV_20 (0x14)
+#define HSIC_CTRL_REFCLKDIV_MASK (0x7f)
+#define HSIC_CTRL_REFCLKDIV_SHIFT (16)
+
+#define HSIC_CTRL_SIDDQ (0x1 << 6)
+#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
+#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
+#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
+#define HSIC_CTRL_UTMISWRST (0x1 << 2)
+#define HSIC_CTRL_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_EHCICTRL EXYNOS4_HSOTG_PHYREG(0x30)
+#define EHCICTRL_ENAINCRXALIGN (0x1 << 29)
+#define EHCICTRL_ENAINCR4 (0x1 << 28)
+#define EHCICTRL_ENAINCR8 (0x1 << 27)
+#define EHCICTRL_ENAINCR16 (0x1 << 26)
+
+#define EXYNOS5_PHY_HOST_OHCICTRL EXYNOS4_HSOTG_PHYREG(0x34)
+#define OHCICTRL_SUSPLGCY (0x1 << 3)
+#define OHCICTRL_APPSTARTCLK (0x1 << 2)
+#define OHCICTRL_CNTSEL (0x1 << 1)
+#define OHCICTRL_CLKCKTRST (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_SYS EXYNOS4_HSOTG_PHYREG(0x38)
+#define OTG_SYS_PHYLINK_SW_RESET (0x1 << 14)
+#define OTG_SYS_LINK_SW_RST_UOTG (0x1 << 13)
+#define OTG_SYS_PHY0_SW_RST (0x1 << 12)
+
+#define OTG_SYS_REF_CLK_SEL_XTAL (0x0)
+#define OTG_SYS_REF_CLK_SEL_EXTL (0x1)
+#define OTG_SYS_REF_CLK_SEL_CLKCORE (0x2)
+#define OTG_SYS_REF_CLK_SEL_MASK (0x3)
+#define OTG_SYS_REF_CLK_SEL_SHIFT (9)
+
+#define OTG_SYS_IP_PULLUP_UOTG (0x1 << 8)
+#define OTG_SYS_COMMON_ON (0x1 << 7)
+#define OTG_SYS_CLKSEL_SHIFT (4)
+#define OTG_SYS_CTRL0_FSEL_MASK (0x7 << 4)
+#define OTG_SYS_FORCE_SLEEP (0x1 << 3)
+#define OTG_SYS_OTGDISABLE (0x1 << 2)
+#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
+#define OTG_SYS_FORCE_SUSPEND (0x1 << 0)
+
#endif /* __PLAT_S5P_REGS_USB_PHY_H */
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c
index e99d3d8f2bcf..dea64559a63a 100644
--- a/arch/arm/mach-exynos/mach-exynos5-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos5-dt.c
@@ -17,15 +17,40 @@
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
+
#include <mach/map.h>
#include <mach/regs-pmu.h>
#include <plat/cpu.h>
#include <plat/regs-serial.h>
#include <plat/mfc.h>
+#include <linux/platform_data/samsung-usbphy.h>
+#include <linux/platform_data/usb-exynos.h>
+
+#include <plat/regs-srom.h>
+#include <plat/devs.h>
+#include <plat/usb-phy.h>
+#include <linux/platform_data/usb-ehci-s5p.h>
#include "common.h"
+
+
+static struct samsung_usbphy_data exynos5_usbphy_pdata = {
+ .pmu_isolation = s5p_usb_phy_pmu_isolation,
+ .phy_cfg_sel = s5p_usb_phy_cfg_sel,
+};
+
+static struct exynos4_ohci_platdata smdk5250_ohci_pdata = {
+ .phy_init = s5p_usb_phy_init,
+ .phy_exit = s5p_usb_phy_exit,
+};
+
+static struct s5p_ehci_platdata smdk5250_ehci_pdata = {
+ .phy_init = s5p_usb_phy_init,
+ .phy_exit = s5p_usb_phy_exit,
+};
+
/*
* The following lookup table is used to override device names when devices
* are registered from device tree. This is temporarily added to enable
@@ -104,6 +129,14 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL),
OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000,
"exynos-tmu", NULL),
+ OF_DEV_AUXDATA("samsung,exynos5250-usbphy", EXYNOS5_PA_HSPHY,
+ "s3c-usbphy", &exynos5_usbphy_pdata),
+ OF_DEV_AUXDATA("samsung,exynos-dwc3", EXYNOS5_PA_DRD,
+ "exynos-dwc3", NULL),
+ OF_DEV_AUXDATA("samsung,exynos-ohci", 0x12120000,
+ "exynos-ohci", &smdk5250_ohci_pdata),
+ OF_DEV_AUXDATA("samsung,exynos-ehci", 0x12110000,
+ "s5p-ehci", &smdk5250_ehci_pdata),
{},
};
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index 57668eb68e75..c957b4fd01b0 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -24,6 +24,7 @@
#include <asm/arch_timer.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
+#include <asm/arch_timer.h>
#include <plat/cpu.h>
@@ -160,6 +161,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);
}
@@ -493,6 +498,9 @@ static void __init exynos_timer_init(void)
exynos4_timer_resources();
exynos4_clocksource_init();
exynos4_clockevent_init();
+
+ if (arch_timer_of_register() != 0)
+ pr_err("Error registering architected timers\n");
}
struct sys_timer exynos4_timer = {
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index b81cc569a8dd..78100981b0be 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -14,24 +14,75 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
#include <mach/regs-pmu.h>
#include <mach/regs-usb-phy.h>
#include <plat/cpu.h>
+#include <plat/map-base.h>
#include <plat/usb-phy.h>
+#define PHY_ENABLE 1
+#define PHY_DISABLE 0
+#define EXYNOS5_USB_CFG (S3C_VA_SYS + 0x230)
+
static atomic_t host_usage;
static int exynos4_usb_host_phy_is_on(void)
{
- return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1;
+ if (soc_is_exynos5250()) {
+ return (readl(EXYNOS5_PHY_HOST_CTRL0) &
+ HOST_CTRL0_PHYSWRSTALL) ? 0 : 1;
+ } else {
+ return (readl(EXYNOS4_PHYPWR) &
+ PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1;
+ }
+}
+
+static void exynos_usb_mux_change(struct platform_device *pdev, int val)
+{
+ u32 is_host;
+ if (soc_is_exynos5250()) {
+ is_host = readl(EXYNOS5_USB_CFG);
+ writel(val, EXYNOS5_USB_CFG);
+ }
+ if (is_host != val)
+ dev_dbg(&pdev->dev, "Change USB MUX from %s to %s",
+ is_host ? "Host" : "Device", val ? "Host" : "Device");
}
-static void exynos4210_usb_phy_clkset(struct platform_device *pdev)
+static struct clk *exynos_usb_clock_enable(struct platform_device *pdev)
+{
+ struct clk *usb_clk = NULL;
+ int err = 0;
+
+ if (soc_is_exynos5250())
+ usb_clk = clk_get(&pdev->dev, "usbhost");
+ else
+ usb_clk = clk_get(&pdev->dev, "otg");
+ if (IS_ERR(usb_clk)) {
+ dev_err(&pdev->dev, "Failed to get otg clock\n");
+ return NULL;
+ }
+
+ err = clk_enable(usb_clk);
+ if (err) {
+ clk_put(usb_clk);
+ return NULL;
+ }
+ return usb_clk;
+}
+
+static int exynos4210_usb_phy_clkset(struct platform_device *pdev)
{
struct clk *xusbxti_clk;
- u32 phyclk;
+ u32 phyclk = 0;
+
+ if (soc_is_exynos5250())
+ xusbxti_clk = clk_get(&pdev->dev, "ext_xtal");
+ else
+ xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
- xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
if (soc_is_exynos4210()) {
/* set clock frequency for PLL */
@@ -77,11 +128,47 @@ static void exynos4210_usb_phy_clkset(struct platform_device *pdev)
break;
}
writel(phyclk, EXYNOS4_PHYCLK);
+ } else if (soc_is_exynos5250()) {
+ /* set clock frequency for PLL */
+ switch (clk_get_rate(xusbxti_clk)) {
+ case 96 * 100000:
+ phyclk |= EXYNOS5_CLKSEL_9600K;
+ break;
+ case 10 * MHZ:
+ phyclk |= EXYNOS5_CLKSEL_10M;
+ break;
+ case 12 * MHZ:
+ phyclk |= EXYNOS5_CLKSEL_12M;
+ break;
+ case 192 * 100000:
+ phyclk |= EXYNOS5_CLKSEL_19200K;
+ break;
+ case 20 * MHZ:
+ phyclk |= EXYNOS5_CLKSEL_20M;
+ break;
+ case 50 * MHZ:
+ phyclk |= EXYNOS5_CLKSEL_50M;
+ break;
+ case 24 * MHZ:
+ default:
+ /* default reference clock */
+ phyclk |= EXYNOS5_CLKSEL_24M;
+ break;
+ }
}
clk_put(xusbxti_clk);
}
+ return phyclk;
}
-
+#if 0
+static void exynos_usb_phy_control(enum usb_phy_type phy_type , int on)
+{
+ if (soc_is_exynos5250()) {
+ if (phy_type & USB_PHY)
+ writel(on, S5P_USBHOST_PHY_CONTROL);
+ }
+}
+#endif
static int exynos4210_usb_phy0_init(struct platform_device *pdev)
{
u32 rstcon;
@@ -120,21 +207,12 @@ static int exynos4210_usb_phy1_init(struct platform_device *pdev)
{
struct clk *otg_clk;
u32 rstcon;
- int err;
atomic_inc(&host_usage);
- otg_clk = clk_get(&pdev->dev, "otg");
- if (IS_ERR(otg_clk)) {
- dev_err(&pdev->dev, "Failed to get otg clock\n");
- return PTR_ERR(otg_clk);
- }
-
- err = clk_enable(otg_clk);
- if (err) {
- clk_put(otg_clk);
- return err;
- }
+ otg_clk = exynos_usb_clock_enable(pdev);
+ if (otg_clk == NULL)
+ dev_err(&pdev->dev, "Failed to enable otg clock\n");
if (exynos4_usb_host_phy_is_on())
return 0;
@@ -173,22 +251,13 @@ static int exynos4210_usb_phy1_init(struct platform_device *pdev)
static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
{
struct clk *otg_clk;
- int err;
if (atomic_dec_return(&host_usage) > 0)
return 0;
- otg_clk = clk_get(&pdev->dev, "otg");
- if (IS_ERR(otg_clk)) {
- dev_err(&pdev->dev, "Failed to get otg clock\n");
- return PTR_ERR(otg_clk);
- }
-
- err = clk_enable(otg_clk);
- if (err) {
- clk_put(otg_clk);
- return err;
- }
+ otg_clk = exynos_usb_clock_enable(pdev);
+ if (otg_clk == NULL)
+ dev_err(&pdev->dev, "Failed to enable otg clock\n");
writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN),
EXYNOS4_PHYPWR);
@@ -202,22 +271,70 @@ static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
return 0;
}
+
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return exynos4210_usb_phy0_init(pdev);
- else if (type == S5P_USB_PHY_HOST)
- return exynos4210_usb_phy1_init(pdev);
+ else if (type == USB_PHY_TYPE_HOST) {
+ return exynos4210_usb_phy1_init(pdev);
+ }
return -EINVAL;
}
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
- return exynos4210_usb_phy0_exit(pdev);
- else if (type == S5P_USB_PHY_HOST)
- return exynos4210_usb_phy1_exit(pdev);
+ if (type == USB_PHY_TYPE_DEVICE)
+ return exynos4210_usb_phy0_exit(pdev);
+ else if (type == USB_PHY_TYPE_HOST) {
+ return exynos4210_usb_phy1_exit(pdev);
+ }
return -EINVAL;
}
+
+ void s5p_usb_phy_pmu_isolation(int on, int type)
+ {
+ if (type == USB_PHY_TYPE_HOST) {
+ if (on)
+ writel(readl(S5P_USBHOST_PHY_CONTROL)
+ & ~S5P_USBHOST_PHY_ENABLE,
+ S5P_USBHOST_PHY_CONTROL);
+ else
+ writel(readl(S5P_USBHOST_PHY_CONTROL)
+ | S5P_USBHOST_PHY_ENABLE,
+ S5P_USBHOST_PHY_CONTROL);
+ }else if(type == USB_PHY_TYPE_DRD) {
+ if (on)
+ writel(readl(S5P_USBDRD_PHY_CONTROL)
+ & ~S5P_USBDRD_PHY_ENABLE,
+ S5P_USBDRD_PHY_CONTROL);
+ else
+ writel(readl(S5P_USBDRD_PHY_CONTROL)
+ | S5P_USBDRD_PHY_ENABLE,
+ S5P_USBDRD_PHY_CONTROL);
+ } else {
+ if (on)
+ writel(readl(S5P_USBDEVICE_PHY_CONTROL)
+ & ~S5P_USBDEVICE_PHY_ENABLE,
+ S5P_USBDEVICE_PHY_CONTROL);
+ else
+ writel(readl(S5P_USBDEVICE_PHY_CONTROL)
+ | S5P_USBDEVICE_PHY_ENABLE,
+ S5P_USBDEVICE_PHY_CONTROL);
+ }
+ }
+
+/* Switch between HOST and OTG link from PHY_CFG */
+void s5p_usb_phy_cfg_sel(struct device *dev, int type)
+{
+ u32 is_host;
+
+ is_host = readl(EXYNOS5_USB_CFG);
+ writel(type, EXYNOS5_USB_CFG);
+
+ if (is_host != type)
+ dev_dbg(dev, "Changed USB MUX from %s to %s",
+ is_host ? "Host" : "Device", type ? "Host" : "Device");
+}
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 87d501ff3328..6bbfe8afb58f 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -134,7 +134,6 @@ extern struct platform_device exynos4_device_spdif;
extern struct platform_device samsung_asoc_idma;
extern struct platform_device samsung_device_keypad;
-
/* s3c2440 specific devices */
#ifdef CONFIG_CPU_S3C2440
diff --git a/arch/arm/plat-samsung/include/plat/usb-phy.h b/arch/arm/plat-samsung/include/plat/usb-phy.h
index 959bcdb03a25..72fb31229127 100644
--- a/arch/arm/plat-samsung/include/plat/usb-phy.h
+++ b/arch/arm/plat-samsung/include/plat/usb-phy.h
@@ -11,12 +11,8 @@
#ifndef __PLAT_SAMSUNG_USB_PHY_H
#define __PLAT_SAMSUNG_USB_PHY_H __FILE__
-enum s5p_usb_phy_type {
- S5P_USB_PHY_DEVICE,
- S5P_USB_PHY_HOST,
-};
-
extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);
-
+extern void s5p_usb_phy_pmu_isolation(int on, int type);
+extern void s5p_usb_phy_cfg_sel(struct device *dev, int type);
#endif /* __PLAT_SAMSUNG_USB_PHY_H */
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 41fc5502c4ac..071c6a73d7f0 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 <mach/cpufreq.h>
@@ -216,8 +218,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);
@@ -239,16 +268,35 @@ 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 exynos4_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *exynos4_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY,
.verify = exynos_verify_speed,
.target = exynos_target,
.get = exynos_getspeed,
.init = exynos_cpufreq_cpu_init,
+ .exit = exynos4_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
+ .attr = exynos4_cpufreq_attr,
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
@@ -289,6 +337,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/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 49d361a618d0..9252ae944393 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
@@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = {
},
};
+#ifdef CONFIG_OF
+static struct of_device_id sec_dt_match[] = {
+ { .compatible = "samsung,s5m8767-pmic",
+ .data = S5M8767X,
+ },
+ {},
+};
+#endif
+
int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest)
{
return regmap_read(sec_pmic->regmap, reg, dest);
@@ -95,6 +105,59 @@ static struct regmap_config sec_regmap_config = {
.val_bits = 8,
};
+
+#ifdef CONFIG_OF
+/*
+ * Only the common platform data elements for s5m8767 are parsed here from the
+ * device tree. Other sub-modules of s5m8767 such as pmic, rtc and others have
+ * to parse their own platform data elements from device tree.
+ *
+ * The s5m8767 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ struct sec_platform_data *pd;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "could not allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pd->ono = irq_of_parse_and_map(dev->of_node, 1);
+
+ /*
+ * ToDo: the 'wakeup' member in the platform data is more of a linux
+ * specfic information. Hence, there is no binding for that yet and
+ * not parsed here.
+ */
+
+ return pd;
+}
+#else
+static struct sec_platform_data *sec_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+#ifdef CONFIG_OF
+ if (i2c->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(sec_dt_match, i2c->dev.of_node);
+ return (int)match->data;
+ }
+#endif
+ return (int)id->driver_data;
+}
+
static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -111,13 +174,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_pmic->dev = &i2c->dev;
sec_pmic->i2c = i2c;
sec_pmic->irq = i2c->irq;
- sec_pmic->type = id->driver_data;
-
+ sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
+
+ if (sec_pmic->dev->of_node) {
+ pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ return ret;
+ }
+ pdata->device_type = sec_pmic->type;
+ }
if (pdata) {
sec_pmic->device_type = pdata->device_type;
sec_pmic->ono = pdata->ono;
sec_pmic->irq_base = pdata->irq_base;
sec_pmic->wakeup = pdata->wakeup;
+ sec_pmic->pdata = pdata;
}
sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
@@ -192,6 +264,7 @@ static struct i2c_driver sec_pmic_driver = {
.driver = {
.name = "sec_pmic",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sec_dt_match),
},
.probe = sec_pmic_probe,
.remove = sec_pmic_remove,
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 7a6e758f48e7..89879ea1dc2f 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;
@@ -66,6 +95,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/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 33b65c9ad5d5..534ff7920754 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -14,6 +14,7 @@
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -21,6 +22,11 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s5m8767.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/io.h>
+#include <mach/map.h>
+
+#define S5M8767_OPMODE_NORMAL_MODE 0x1
struct s5m8767_info {
struct device *dev;
@@ -306,7 +312,7 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
int reg, mask, ret;
int reg_id = rdev_get_id(rdev);
- unsigned int val;
+ int val;
ret = s5m8767_get_voltage_register(rdev, &reg);
if (ret)
@@ -508,15 +514,200 @@ static struct regulator_desc regulators[] = {
s5m8767_regulator_desc(BUCK9),
};
+#ifdef CONFIG_OF
+static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
+ struct sec_platform_data *pdata,
+ struct device_node *pmic_np)
+{
+ int i, gpio;
+
+ for (i = 0; i < 3; i++) {
+ gpio = of_get_named_gpio(pmic_np,
+ "s5m8767,pmic-buck-dvs-gpios", i);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+ return -EINVAL;
+ }
+ pdata->buck_gpios[i] = gpio;
+ }
+ return 0;
+}
+
+static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
+ struct sec_platform_data *pdata,
+ struct device_node *pmic_np)
+{
+ int i, gpio;
+
+ for (i = 0; i < 3; i++) {
+ gpio = of_get_named_gpio(pmic_np,
+ "s5m8767,pmic-buck-ds-gpios", i);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+ return -EINVAL;
+ }
+ pdata->buck_ds[i] = gpio;
+ }
+ return 0;
+}
+
+static int s5m8767_pmic_dt_parse_pdata(struct sec_pmic_dev *iodev,
+ struct sec_platform_data *pdata)
+{
+ struct device_node *pmic_np, *regulators_np, *reg_np;
+ struct sec_regulator_data *rdata;
+ struct sec_opmode_data *rmode;
+ unsigned int i, dvs_voltage_nr = 1, ret;
+
+ pmic_np = iodev->dev->of_node;
+ if (!pmic_np) {
+ dev_err(iodev->dev, "could not find pmic sub-node\n");
+ return -ENODEV;
+ }
+
+ regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ if (!regulators_np) {
+ dev_err(iodev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ /* count the number of regulators to be supported in pmic */
+ pdata->num_regulators = 0;
+ for_each_child_of_node(regulators_np, reg_np) {
+ pdata->num_regulators++;
+ }
+
+ rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ dev_err(iodev->dev, "could not allocate memory for "
+ "regulator data\n");
+ return -ENOMEM;
+ }
+
+ rmode = devm_kzalloc(iodev->dev, sizeof(*rmode) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ dev_err(iodev->dev, "could not allocate memory for "
+ "regulator mode\n");
+ return -ENOMEM;
+ }
+
+
+ pdata->regulators = rdata;
+ pdata->opmode = rmode;
+ for_each_child_of_node(regulators_np, reg_np) {
+ for (i = 0; i < ARRAY_SIZE(regulators); i++)
+ if (!of_node_cmp(reg_np->name, regulators[i].name))
+ break;
+
+ if (i == ARRAY_SIZE(regulators)) {
+ dev_warn(iodev->dev, "don't know how to configure "
+ "regulator %s\n", reg_np->name);
+ continue;
+ }
+
+ rdata->id = i;
+ rdata->initdata = of_get_regulator_init_data(
+ iodev->dev, reg_np);
+ rdata->reg_node = reg_np;
+ rdata++;
+ rmode->id = i;
+ if (of_property_read_u32(reg_np, "op_mode",
+ &rmode->mode)) {
+ dev_warn(iodev->dev, "no op_mode property property at %s\n",
+ reg_np->full_name);
+ /*
+ * Set operating mode to NORMAL "ON" as default. The
+ * 32KHz clocks are being turned on and kept on by
+ * default, so the below mode setting does not impact
+ * it.
+ */
+ rmode->mode = S5M8767_OPMODE_NORMAL_MODE;
+ }
+ rmode++;
+ }
+
+ if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL))
+ pdata->buck2_gpiodvs = true;
+
+ if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL))
+ pdata->buck3_gpiodvs = true;
+
+ if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL))
+ pdata->buck4_gpiodvs = true;
+
+ if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+ pdata->buck4_gpiodvs) {
+ ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+ if (ret)
+ return -EINVAL;
+
+ if (of_property_read_u32(pmic_np,
+ "s5m8767,pmic-buck-default-dvs-idx",
+ &pdata->buck_default_idx)) {
+ pdata->buck_default_idx = 0;
+ } else {
+ if (pdata->buck_default_idx >= 8) {
+ pdata->buck_default_idx = 0;
+ dev_info(iodev->dev, "invalid value for "
+ "default dvs index, using 0 instead\n");
+ }
+ }
+
+ dvs_voltage_nr = 8;
+ }
+
+ ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);
+ if (ret)
+ return -EINVAL;
+
+ if (of_property_read_u32_array(pmic_np,
+ "s5m8767,pmic-buck2-dvs-voltage",
+ pdata->buck2_voltage, dvs_voltage_nr)) {
+ dev_err(iodev->dev, "buck2 voltages not specified\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_array(pmic_np,
+ "s5m8767,pmic-buck3-dvs-voltage",
+ pdata->buck3_voltage, dvs_voltage_nr)) {
+ dev_err(iodev->dev, "buck3 voltages not specified\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_array(pmic_np,
+ "s5m8767,pmic-buck4-dvs-voltage",
+ pdata->buck4_voltage, dvs_voltage_nr)) {
+ dev_err(iodev->dev, "buck4 voltages not specified\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+static int s5m8767_pmic_dt_parse_pdata(struct sec_pmic_dev *iodev,
+ struct sec_platform_data *pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
static int s5m8767_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct sec_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
struct regulator_dev **rdev;
struct s5m8767_info *s5m8767;
int i, ret, size, buck_init;
+ if (iodev->dev->of_node) {
+ ret = s5m8767_pmic_dt_parse_pdata(iodev, pdata);
+ if (ret)
+ return ret;
+ }
+
if (!pdata) {
dev_err(pdev->dev.parent, "Platform data not supplied\n");
return -ENODEV;
@@ -765,6 +956,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
config.dev = s5m8767->dev;
config.init_data = pdata->regulators[i].initdata;
config.driver_data = s5m8767;
+ config.of_node = pdata->regulators[i].reg_node;
rdev[i] = regulator_register(&regulators[id], &config);
if (IS_ERR(rdev[i])) {
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 224751e9f5ff..25b364909a45 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -82,7 +82,7 @@
#define EXYNOS_TRIMINFO_RELOAD 0x1
#define EXYNOS_TMU_CLEAR_RISE_INT 0x111
-#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 16)
+#define EXYNOS_TMU_CLEAR_FALL_INT (0x111 << 12)
#define EXYNOS_MUX_ADDR_VALUE 6
#define EXYNOS_MUX_ADDR_SHIFT 20
#define EXYNOS_TMU_TRIP_MODE_SHIFT 13
@@ -94,6 +94,7 @@
#define SENSOR_NAME_LEN 16
#define MAX_TRIP_COUNT 8
#define MAX_COOLING_DEVICE 4
+#define MAX_THRESHOLD_LEVS 4
#define ACTIVE_INTERVAL 500
#define IDLE_INTERVAL 10000
@@ -125,6 +126,7 @@ struct exynos_tmu_data {
struct thermal_trip_point_conf {
int trip_val[MAX_TRIP_COUNT];
int trip_count;
+ u8 trigger_falling;
};
struct thermal_cooling_conf {
@@ -174,7 +176,8 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
mutex_lock(&th_zone->therm_dev->lock);
- if (mode == THERMAL_DEVICE_ENABLED)
+ if (mode == THERMAL_DEVICE_ENABLED &&
+ !th_zone->sensor_conf->trip_data.trigger_falling)
th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
else
th_zone->therm_dev->polling_delay = 0;
@@ -284,7 +287,7 @@ static int exynos_bind(struct thermal_zone_device *thermal,
case MONITOR_ZONE:
case WARN_ZONE:
if (thermal_zone_bind_cooling_device(thermal, i, cdev,
- level, level)) {
+ level, 0)) {
pr_err("error binding cdev inst %d\n", i);
ret = -EINVAL;
}
@@ -362,12 +365,19 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
static int exynos_get_trend(struct thermal_zone_device *thermal,
int trip, enum thermal_trend *trend)
{
- if (thermal->temperature >= trip)
- *trend = THERMAL_TREND_RAISING;
+ int ret = 0;
+ unsigned long trip_temp;
+
+ ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
+ if (ret < 0)
+ return ret;
+
+ if (thermal->temperature >= trip_temp)
+ *trend = THERMAL_TREND_RAISE_FULL;
else
- *trend = THERMAL_TREND_DROPPING;
+ *trend = THERMAL_TREND_DROP_FULL;
- return 0;
+ return ret;
}
/* Operation callback functions for thermal zone */
static struct thermal_zone_device_ops const exynos_dev_ops = {
@@ -413,7 +423,8 @@ static void exynos_report_trigger(void)
break;
}
- if (th_zone->mode == THERMAL_DEVICE_ENABLED) {
+ if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
+ !th_zone->sensor_conf->trip_data.trigger_falling) {
if (i > 0)
th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
else
@@ -452,7 +463,8 @@ static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
- IDLE_INTERVAL);
+ sensor_conf->trip_data.trigger_falling ?
+ 0 : IDLE_INTERVAL);
if (IS_ERR(th_zone->therm_dev)) {
pr_err("Failed to register thermal zone device\n");
@@ -559,8 +571,9 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata = data->pdata;
- unsigned int status, trim_info, rising_threshold;
- int ret = 0, threshold_code;
+ unsigned int status, trim_info;
+ unsigned int rising_threshold = 0, falling_threshold = 0;
+ int ret = 0, threshold_code, i, trigger_levs = 0;
mutex_lock(&data->lock);
clk_enable(data->clk);
@@ -585,6 +598,11 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
(data->temp_error2 != 0))
data->temp_error1 = pdata->efuse_value;
+ /* Count trigger levels to be enabled */
+ for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
+ if (pdata->trigger_levels[i])
+ trigger_levs++;
+
if (data->soc == SOC_ARCH_EXYNOS4210) {
/* Write temperature code for threshold */
threshold_code = temp_to_code(data, pdata->threshold);
@@ -594,44 +612,38 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
}
writeb(threshold_code,
data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
-
- writeb(pdata->trigger_levels[0],
- data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0);
- writeb(pdata->trigger_levels[1],
- data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL1);
- writeb(pdata->trigger_levels[2],
- data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL2);
- writeb(pdata->trigger_levels[3],
- data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL3);
+ for (i = 0; i < trigger_levs; i++)
+ writeb(pdata->trigger_levels[i],
+ data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
writel(EXYNOS4210_TMU_INTCLEAR_VAL,
data->base + EXYNOS_TMU_REG_INTCLEAR);
} else if (data->soc == SOC_ARCH_EXYNOS) {
- /* Write temperature code for threshold */
- threshold_code = temp_to_code(data, pdata->trigger_levels[0]);
- if (threshold_code < 0) {
- ret = threshold_code;
- goto out;
- }
- rising_threshold = threshold_code;
- threshold_code = temp_to_code(data, pdata->trigger_levels[1]);
- if (threshold_code < 0) {
- ret = threshold_code;
- goto out;
- }
- rising_threshold |= (threshold_code << 8);
- threshold_code = temp_to_code(data, pdata->trigger_levels[2]);
- if (threshold_code < 0) {
- ret = threshold_code;
- goto out;
+ /* Write temperature code for rising and falling threshold */
+ for (i = 0; i < trigger_levs; i++) {
+ threshold_code = temp_to_code(data,
+ pdata->trigger_levels[i]);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
+ rising_threshold |= threshold_code << 8 * i;
+ if (pdata->threshold_falling) {
+ threshold_code = temp_to_code(data,
+ pdata->trigger_levels[i] -
+ pdata->threshold_falling);
+ if (threshold_code > 0)
+ falling_threshold |=
+ threshold_code << 8 * i;
+ }
}
- rising_threshold |= (threshold_code << 16);
writel(rising_threshold,
data->base + EXYNOS_THD_TEMP_RISE);
- writel(0, data->base + EXYNOS_THD_TEMP_FALL);
+ writel(falling_threshold,
+ data->base + EXYNOS_THD_TEMP_FALL);
- writel(EXYNOS_TMU_CLEAR_RISE_INT|EXYNOS_TMU_CLEAR_FALL_INT,
+ writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
data->base + EXYNOS_TMU_REG_INTCLEAR);
}
out:
@@ -664,6 +676,8 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
pdata->trigger_level2_en << 8 |
pdata->trigger_level1_en << 4 |
pdata->trigger_level0_en;
+ if (pdata->threshold_falling)
+ interrupt_en |= interrupt_en << 16;
} else {
con |= EXYNOS_TMU_CORE_OFF;
interrupt_en = 0; /* Disable all interrupts */
@@ -701,16 +715,19 @@ static void exynos_tmu_work(struct work_struct *work)
clk_enable(data->clk);
+
+ clk_disable(data->clk);
+ mutex_unlock(&data->lock);
+ exynos_report_trigger();
+ clk_enable(data->clk);
if (data->soc == SOC_ARCH_EXYNOS)
- writel(EXYNOS_TMU_CLEAR_RISE_INT,
+ writel(EXYNOS_TMU_CLEAR_RISE_INT |
+ EXYNOS_TMU_CLEAR_FALL_INT,
data->base + EXYNOS_TMU_REG_INTCLEAR);
else
writel(EXYNOS4210_TMU_INTCLEAR_VAL,
data->base + EXYNOS_TMU_REG_INTCLEAR);
-
clk_disable(data->clk);
- mutex_unlock(&data->lock);
- exynos_report_trigger();
enable_irq(data->irq);
}
@@ -759,6 +776,7 @@ static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
+ .threshold_falling = 10,
.trigger_levels[0] = 85,
.trigger_levels[1] = 103,
.trigger_levels[2] = 110,
@@ -916,6 +934,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
exynos_sensor_conf.trip_data.trip_val[i] =
pdata->threshold + pdata->trigger_levels[i];
+ exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
+
exynos_sensor_conf.cooling_data.freq_clip_count =
pdata->freq_tab_count;
for (i = 0; i < pdata->freq_tab_count; i++) {
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 0cd5e9fbab1c..d846aa03fc45 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -35,6 +35,10 @@
* state for this trip point
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
* state for this trip point
+ * c. if the trend is THERMAL_TREND_RAISE_FULL, use highest cooling
+ * state for this trip point
+ * d. if the trend is THERMAL_TREND_DROP_FULL, use lowest cooling
+ * state for this trip point
*/
static unsigned long get_target_state(struct thermal_instance *instance,
enum thermal_trend trend)
@@ -50,7 +54,10 @@ static unsigned long get_target_state(struct thermal_instance *instance,
} else if (trend == THERMAL_TREND_DROPPING) {
cur_state = cur_state > instance->lower ?
(cur_state - 1) : instance->lower;
- }
+ } else if (trend == THERMAL_TREND_RAISE_FULL)
+ cur_state = instance->upper;
+ else if (trend == THERMAL_TREND_DROP_FULL)
+ cur_state = instance->lower;
return cur_state;
}
@@ -87,7 +94,8 @@ static void update_instance_for_throttle(struct thermal_zone_device *tz,
}
static void update_instance_for_dethrottle(struct thermal_zone_device *tz,
- int trip, enum thermal_trip_type trip_type)
+ int trip, enum thermal_trip_type trip_type,
+ enum thermal_trend trend)
{
struct thermal_instance *instance;
struct thermal_cooling_device *cdev;
@@ -101,7 +109,10 @@ static void update_instance_for_dethrottle(struct thermal_zone_device *tz,
cdev = instance->cdev;
cdev->ops->get_cur_state(cdev, &cur_state);
- instance->target = cur_state > instance->lower ?
+ if (trend == THERMAL_TREND_DROP_FULL)
+ instance->target = instance->lower;
+ else
+ instance->target = cur_state > instance->lower ?
(cur_state - 1) : THERMAL_NO_TARGET;
/* Deactivate a passive thermal instance */
@@ -133,7 +144,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
if (tz->temperature >= trip_temp)
update_instance_for_throttle(tz, trip, trip_type, trend);
else
- update_instance_for_dethrottle(tz, trip, trip_type);
+ update_instance_for_dethrottle(tz, trip, trip_type, trend);
mutex_unlock(&tz->lock);
}
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index e514b3a4dc57..1f5f8793945a 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -299,7 +299,9 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
ignore_char:
continue;
}
+ spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(tty);
+ return IRQ_HANDLED;
out:
spin_unlock_irqrestore(&port->lock, flags);
@@ -1011,6 +1013,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);
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 640ae6c6d2d2..f39c215371b7 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -54,6 +54,7 @@ config USB_ARCH_HAS_EHCI
# some non-PCI HCDs implement xHCI
config USB_ARCH_HAS_XHCI
boolean
+ default y if ARCH_EXYNOS5
default PCI
menuconfig USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index f5ed3d75fa5a..6c21c9187c37 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_OTG_UTILS) += otg/
+obj-$(CONFIG_USB_COMMON) += phy/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/
@@ -46,7 +47,6 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
-obj-$(CONFIG_USB_COMMON) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 2a89588def06..b2d007565180 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -836,7 +836,6 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
unsigned delay;
u16 wHubCharacteristics =
le16_to_cpu(hub->descriptor->wHubCharacteristics);
-
/* Enable power on each port. Some hubs have reserved values
* of LPSM (> 2) in their descriptors, even though they are
* USB 2.0 hubs. Some hubs do not implement port-power switching
@@ -1019,7 +1018,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
int status;
bool need_debounce_delay = false;
unsigned delay;
-
/* Continue a partial initialization */
if (type == HUB_INIT2)
goto init2;
@@ -1100,7 +1098,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
struct usb_device *udev = hub->ports[port1 - 1]->child;
u16 portstatus, portchange;
-
portstatus = portchange = 0;
status = hub_port_status(hub, port1, &portstatus, &portchange);
if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
@@ -1386,7 +1383,7 @@ static int hub_configure(struct usb_hub *hub,
}
hdev->maxchild = hub->descriptor->bNbrPorts;
- dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
+ dev_dbg (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s");
hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *),
@@ -1397,7 +1394,6 @@ static int hub_configure(struct usb_hub *hub,
}
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
-
/* FIXME for USB 3.0, skip for now */
if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
!(hub_is_superspeed(hdev))) {
@@ -1410,9 +1406,9 @@ static int hub_configure(struct usb_hub *hub,
? 'F' : 'R';
portstr[hdev->maxchild] = 0;
dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
- } else
+ } else {
dev_dbg(hub_dev, "standalone hub\n");
-
+ }
switch (wHubCharacteristics & HUB_CHAR_LPSM) {
case HUB_CHAR_COMMON_LPSM:
dev_dbg(hub_dev, "ganged power switching\n");
@@ -1743,7 +1739,7 @@ descriptor_error:
goto descriptor_error;
/* We found a hub */
- dev_info (&intf->dev, "USB hub found\n");
+ dev_dbg (&intf->dev, "USB hub found\n");
hub = kzalloc(sizeof(*hub), GFP_KERNEL);
if (!hub) {
@@ -1770,7 +1766,6 @@ descriptor_error:
if (hub_configure(hub, endpoint) >= 0)
return 0;
-
hub_disconnect (intf);
return -ENODEV;
}
@@ -2062,7 +2057,7 @@ void usb_disconnect(struct usb_device **pdev)
* this quiesces everything except pending urbs.
*/
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- dev_info(&udev->dev, "USB disconnect, device number %d\n",
+ dev_dbg(&udev->dev, "USB disconnect, device number %d\n",
udev->devnum);
usb_lock_device(udev);
@@ -2115,10 +2110,10 @@ static void show_string(struct usb_device *udev, char *id, char *string)
static void announce_device(struct usb_device *udev)
{
- dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
+ dev_dbg(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- dev_info(&udev->dev,
+ dev_dbg(&udev->dev,
"New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
@@ -2164,7 +2159,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
if (desc->bmAttributes & USB_OTG_HNP) {
unsigned port1 = udev->portnum;
- dev_info(&udev->dev,
+ dev_dbg(&udev->dev,
"Dual-Role OTG device on %sHNP port\n",
(port1 == bus->otg_port)
? "" : "non-");
@@ -2183,7 +2178,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
/* OTG MESSAGE: report errors here,
* customize to match your product.
*/
- dev_info(&udev->dev,
+ dev_dbg(&udev->dev,
"can't set HNP mode: %d\n",
err);
bus->b_hnp_enable = 0;
@@ -2466,7 +2461,7 @@ int usb_authorize_device(struct usb_device *usb_dev)
* set other configurations. */
}
}
- dev_info(&usb_dev->dev, "authorized to connect\n");
+ dev_dbg(&usb_dev->dev, "authorized to connect\n");
error_enumerate:
error_device_descriptor:
@@ -3996,7 +3991,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
speed = usb_speed_string(udev->speed);
if (udev->speed != USB_SPEED_SUPER)
- dev_info(&udev->dev,
+ dev_dbg(&udev->dev,
"%s %s USB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed,
devnum, udev->bus->controller->driver->name);
@@ -4110,7 +4105,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (udev->speed == USB_SPEED_SUPER) {
devnum = udev->devnum;
- dev_info(&udev->dev,
+ dev_dbg(&udev->dev,
"%s SuperSpeed USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
devnum, udev->bus->controller->driver->name);
@@ -4222,7 +4217,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)
status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0,
qual, sizeof *qual);
if (status == sizeof *qual) {
- dev_info(&udev->dev, "not running at top speed; "
+ dev_dbg(&udev->dev, "not running at top speed; "
"connect to a high speed hub\n");
/* hub LEDs are probably harder to miss than syslog */
if (hub->has_indicators) {
@@ -4291,7 +4286,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
le16_to_cpu(hub->descriptor->wHubCharacteristics);
struct usb_device *udev;
int status, i;
-
dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n",
port1, portstatus, portchange, portspeed(hub, portstatus));
@@ -4640,7 +4634,6 @@ static void hub_events(void)
hub->nerrors = 0;
hub->error = 0;
}
-
/* deal with port status changes */
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
if (test_bit(i, hub->busy_bits))
@@ -5052,7 +5045,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
/* Device might have changed firmware (DFU or similar) */
if (descriptors_changed(udev, &descriptor)) {
- dev_info(&udev->dev, "device firmware changed\n");
+ dev_dbg(&udev->dev, "device firmware changed\n");
udev->descriptor = descriptor; /* for disconnect() calls */
goto re_enumerate;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index f81b92572735..cc7ea9fe9ce3 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1002,7 +1002,6 @@ static int __init usb_init(void)
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
-
retval = usb_debugfs_init();
if (retval)
goto out;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index f00c74978b7a..10ee1ca3c616 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -365,12 +365,9 @@ static int dwc3_probe(struct platform_device *pdev)
struct resource *res;
struct dwc3 *dwc;
struct device *dev = &pdev->dev;
-
int ret = -ENOMEM;
-
void __iomem *regs;
void *mem;
-
u8 mode;
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
@@ -472,7 +469,10 @@ static int dwc3_probe(struct platform_device *pdev)
goto err0;
}
- mode = DWC3_MODE(dwc->hwparams.hwparams0);
+// mode = DWC3_MODE(dwc->hwparams.hwparams0);
+ /* Putting controller in Host mode here */
+
+ mode = DWC3_MODE_HOST; /* Just a hack for time being */
switch (mode) {
case DWC3_MODE_DEVICE:
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index aae5328ac771..87f2c28600b1 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -43,6 +43,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
memset(&pdata, 0x00, sizeof(pdata));
pdev = platform_device_alloc("nop_usb_xceiv", 0);
+
if (!pdev)
return -ENOMEM;
@@ -50,6 +51,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
pdata.type = USB_PHY_TYPE_USB2;
ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
+
if (ret)
goto err1;
@@ -103,6 +105,13 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "not enough memory\n");
goto err0;
}
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we move to full device tree support this will vanish off.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
/*
* Right now device-tree probed devices don't get dma_mask set.
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 319dcfaa8735..5f18a32714d1 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -17,6 +17,8 @@
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_data/usb-ehci-s5p.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/samsung_usb_phy.h>
#include <plat/usb-phy.h>
#define EHCI_INSNREG00(base) (base + 0x90)
@@ -32,6 +34,8 @@ struct s5p_ehci_hcd {
struct device *dev;
struct usb_hcd *hcd;
struct clk *clk;
+ struct usb_phy *phy;
+ struct s5p_ehci_platdata *pdata;
};
static const struct hc_driver s5p_ehci_hc_driver = {
@@ -65,6 +69,50 @@ static const struct hc_driver s5p_ehci_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
+static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci)
+{
+ struct platform_device *pdev = to_platform_device(s5p_ehci->dev);
+
+ if (s5p_ehci->phy) {
+ samsung_usbphy_set_type(s5p_ehci->phy, USB_PHY_TYPE_HOST);
+ usb_phy_init(s5p_ehci->phy);
+ } else if (s5p_ehci->pdata->phy_init) {
+ s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
+ }
+}
+
+static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci)
+{
+ struct platform_device *pdev = to_platform_device(s5p_ehci->dev);
+
+ if (s5p_ehci->phy) {
+ samsung_usbphy_set_type(s5p_ehci->phy, USB_PHY_TYPE_HOST);
+ usb_phy_shutdown(s5p_ehci->phy);
+ } else if (s5p_ehci->pdata->phy_exit) {
+ s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
+ }
+}
+
+static void s5p_setup_hub_gpio(struct platform_device *pdev, const char *propname, int level)
+{
+ int err;
+ int gpio;
+
+ if (!pdev->dev.of_node)
+ return;
+
+ gpio = of_get_named_gpio(pdev->dev.of_node, propname, 0);
+ if (!gpio_is_valid(gpio))
+ return;
+
+ err = gpio_request_one(gpio, level, "ehci_vbus_gpio");
+
+ if (err)
+ dev_err(&pdev->dev, "can't request ehci hub-reset gpio %d", gpio);
+ else
+ gpio_free(gpio);
+}
+
static void s5p_setup_vbus_gpio(struct platform_device *pdev)
{
int err;
@@ -87,20 +135,15 @@ static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
static int s5p_ehci_probe(struct platform_device *pdev)
{
- struct s5p_ehci_platdata *pdata;
+ struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
struct s5p_ehci_hcd *s5p_ehci;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct resource *res;
+ struct usb_phy *phy;
int irq;
int err;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data defined\n");
- return -EINVAL;
- }
-
/*
* Right now device-tree probed devices don't get dma_mask set.
* Since shared usb code relies on it, set it here for now.
@@ -118,6 +161,19 @@ static int s5p_ehci_probe(struct platform_device *pdev)
if (!s5p_ehci)
return -ENOMEM;
+ phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
+
+ if (IS_ERR_OR_NULL(phy)) {
+ /* Fallback to pdata */
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data or transceiver defined\n");
+ return -EPROBE_DEFER;
+ } else {
+ s5p_ehci->pdata = pdata;
+ }
+ } else {
+ s5p_ehci->phy = phy;
+ }
s5p_ehci->dev = &pdev->dev;
hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
@@ -163,8 +219,14 @@ static int s5p_ehci_probe(struct platform_device *pdev)
goto fail_io;
}
- if (pdata->phy_init)
- pdata->phy_init(pdev, S5P_USB_PHY_HOST);
+ s5p_setup_hub_gpio(pdev, "samsung,hub-reset", GPIOF_OUT_INIT_LOW);
+ s5p_setup_hub_gpio(pdev, "samsung,hub-connect", GPIOF_OUT_INIT_LOW);
+
+ s5p_ehci_phy_enable(s5p_ehci);
+
+ mdelay(1);
+ s5p_setup_hub_gpio(pdev, "samsung,hub-reset", GPIOF_OUT_INIT_HIGH);
+ s5p_setup_hub_gpio(pdev, "samsung,hub-connect", GPIOF_OUT_INIT_HIGH);
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
@@ -175,13 +237,15 @@ static int s5p_ehci_probe(struct platform_device *pdev)
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
- goto fail_io;
+ goto fail_add_hcd;
}
platform_set_drvdata(pdev, s5p_ehci);
return 0;
+fail_add_hcd:
+ s5p_ehci_phy_disable(s5p_ehci);
fail_io:
clk_disable_unprepare(s5p_ehci->clk);
fail_clk:
@@ -197,8 +261,7 @@ static int s5p_ehci_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
- if (pdata && pdata->phy_exit)
- pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
+ s5p_ehci_phy_disable(s5p_ehci);
clk_disable_unprepare(s5p_ehci->clk);
@@ -222,16 +285,12 @@ static int s5p_ehci_suspend(struct device *dev)
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
struct usb_hcd *hcd = s5p_ehci->hcd;
bool do_wakeup = device_may_wakeup(dev);
- struct platform_device *pdev = to_platform_device(dev);
- struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
int rc;
rc = ehci_suspend(hcd, do_wakeup);
- if (pdata && pdata->phy_exit)
- pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
-
- clk_disable_unprepare(s5p_ehci->clk);
+ s5p_ehci_phy_disable(s5p_ehci);
+ clk_disable(s5p_ehci->clk);
return rc;
}
@@ -240,14 +299,10 @@ static int s5p_ehci_resume(struct device *dev)
{
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
struct usb_hcd *hcd = s5p_ehci->hcd;
- struct platform_device *pdev = to_platform_device(dev);
- struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
clk_prepare_enable(s5p_ehci->clk);
- if (pdata && pdata->phy_init)
- pdata->phy_init(pdev, S5P_USB_PHY_HOST);
-
+ s5p_ehci_phy_enable(s5p_ehci);
/* DMA burst Enable */
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index aa3b8844bb9f..f3dcae4f3d85 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -15,12 +15,16 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/platform_data/usb-exynos.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/samsung_usb_phy.h>
#include <plat/usb-phy.h>
struct exynos_ohci_hcd {
struct device *dev;
struct usb_hcd *hcd;
struct clk *clk;
+ struct usb_phy *phy;
+ struct exynos4_ohci_platdata *pdata;
};
static int ohci_exynos_reset(struct usb_hcd *hcd)
@@ -28,6 +32,30 @@ static int ohci_exynos_reset(struct usb_hcd *hcd)
return ohci_init(hcd_to_ohci(hcd));
}
+static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci)
+{
+ struct platform_device *pdev = to_platform_device(exynos_ohci->dev);
+
+ if (exynos_ohci->phy) {
+ samsung_usbphy_set_type(exynos_ohci->phy, USB_PHY_TYPE_HOST);
+ usb_phy_init(exynos_ohci->phy);
+ } else if (exynos_ohci->pdata->phy_init) {
+ exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
+ }
+}
+
+static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci)
+{
+ struct platform_device *pdev = to_platform_device(exynos_ohci->dev);
+
+ if (exynos_ohci->phy) {
+ samsung_usbphy_set_type(exynos_ohci->phy, USB_PHY_TYPE_HOST);
+ usb_phy_shutdown(exynos_ohci->phy);
+ } else if (exynos_ohci->pdata->phy_exit) {
+ exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
+ }
+}
+
static int ohci_exynos_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
@@ -78,11 +106,12 @@ static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32);
static int exynos_ohci_probe(struct platform_device *pdev)
{
- struct exynos4_ohci_platdata *pdata;
+ struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
struct exynos_ohci_hcd *exynos_ohci;
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
struct resource *res;
+ struct usb_phy *phy;
int irq;
int err;
@@ -106,7 +135,19 @@ static int exynos_ohci_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!exynos_ohci)
return -ENOMEM;
-
+ phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
+
+ if (IS_ERR_OR_NULL(phy)) {
+ /* Fallback to pdata */
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data or transceiver defined\n");
+ return -EPROBE_DEFER;
+ } else {
+ exynos_ohci->pdata = pdata;
+ }
+ } else {
+ exynos_ohci->phy = phy;
+ }
exynos_ohci->dev = &pdev->dev;
hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
@@ -152,22 +193,21 @@ static int exynos_ohci_probe(struct platform_device *pdev)
goto fail_io;
}
- if (pdata->phy_init)
- pdata->phy_init(pdev, S5P_USB_PHY_HOST);
-
+ exynos_ohci_phy_enable(exynos_ohci);
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
- goto fail_io;
+ goto fail_add_hcd;
}
platform_set_drvdata(pdev, exynos_ohci);
return 0;
-
+fail_add_hcd:
+ exynos_ohci_phy_disable(exynos_ohci);
fail_io:
clk_disable_unprepare(exynos_ohci->clk);
fail_clk:
@@ -177,16 +217,14 @@ fail_clk:
static int exynos_ohci_remove(struct platform_device *pdev)
{
- struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
struct usb_hcd *hcd = exynos_ohci->hcd;
usb_remove_hcd(hcd);
- if (pdata && pdata->phy_exit)
- pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
-
- clk_disable_unprepare(exynos_ohci->clk);
+ exynos_ohci_phy_disable(exynos_ohci);
+ clk_disable(exynos_ohci->clk);
+ clk_put(exynos_ohci->clk);
usb_put_hcd(hcd);
@@ -208,8 +246,6 @@ static int exynos_ohci_suspend(struct device *dev)
struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
struct usb_hcd *hcd = exynos_ohci->hcd;
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- struct platform_device *pdev = to_platform_device(dev);
- struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
unsigned long flags;
int rc = 0;
@@ -228,10 +264,8 @@ static int exynos_ohci_suspend(struct device *dev)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- if (pdata && pdata->phy_exit)
- pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
-
- clk_disable_unprepare(exynos_ohci->clk);
+ exynos_ohci_phy_disable(exynos_ohci);
+ clk_disable(exynos_ohci->clk);
fail:
spin_unlock_irqrestore(&ohci->lock, flags);
@@ -243,13 +277,12 @@ static int exynos_ohci_resume(struct device *dev)
{
struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
struct usb_hcd *hcd = exynos_ohci->hcd;
- struct platform_device *pdev = to_platform_device(dev);
- struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
clk_prepare_enable(exynos_ohci->clk);
- if (pdata && pdata->phy_init)
- pdata->phy_init(pdev, S5P_USB_PHY_HOST);
+ exynos_ohci_phy_enable(exynos_ohci);
+ /* Mark hardware accessible again as we are out of D3 state by now */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
ohci_resume(hcd, false);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index df90fe51b4aa..2d163d821535 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -93,7 +93,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (usb_disabled())
return -ENODEV;
-
driver = &xhci_plat_xhci_driver;
irq = platform_get_irq(pdev, 0);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 849470b18831..8d08e03fb645 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4607,7 +4607,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
struct device *dev = hcd->self.controller;
int retval;
u32 temp;
-
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
/* XHCI controllers don't stop the ep queue on short packets :| */
@@ -4700,7 +4699,6 @@ MODULE_LICENSE("GPL");
static int __init xhci_hcd_init(void)
{
int retval;
-
retval = xhci_register_pci();
if (retval < 0) {
printk(KERN_DEBUG "Problem registering PCI driver.");
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index a30c04115115..29a45d7fb4b7 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -28,10 +28,8 @@ static struct usb_phy *__usb_find_phy(struct list_head *list,
list_for_each_entry(phy, list, head) {
if (phy->type != type)
continue;
-
return phy;
}
-
return ERR_PTR(-ENODEV);
}
@@ -65,7 +63,6 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
-
phy = usb_get_phy(type);
if (!IS_ERR(phy)) {
*ptr = phy;
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 5de6e7f39f9c..989cbb8a7ac0 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -45,3 +45,10 @@ config USB_RCAR_PHY
To compile this driver as a module, choose M here: the
module will be called rcar-phy.
+
+config SAMSUNG_USBPHY
+ bool "Samsung USB PHY controller Driver"
+ select USB_OTG_UTILS
+ help
+ Enable this to support Samsung USB phy controller for samsung
+ SoCs.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 1a579a860a03..ec304f642402 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_USB_ISP1301) += isp1301.o
obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o
obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY) += samsung-usbphy.o
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
new file mode 100644
index 000000000000..c790c8916f09
--- /dev/null
+++ b/drivers/usb/phy/samsung-usbphy.c
@@ -0,0 +1,1004 @@
+/*
+copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB-PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define SAMSUNG_PHYPWR (0x00)
+
+#define PHYPWR_NORMAL_MASK (0x19 << 0)
+#define PHYPWR_OTG_DISABLE (0x1 << 4)
+#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3)
+#define PHYPWR_FORCE_SUSPEND (0x1 << 1)
+/* For Exynos4 */
+#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
+#define PHYPWR_SLEEP_PHY0 (0x1 << 5)
+
+#define SAMSUNG_PHYCLK (0x04)
+
+#define PHYCLK_MODE_USB11 (0x1 << 6)
+#define PHYCLK_EXT_OSC (0x1 << 5)
+#define PHYCLK_COMMON_ON_N (0x1 << 4)
+#define PHYCLK_ID_PULL (0x1 << 2)
+#define PHYCLK_CLKSEL_MASK (0x3 << 0)
+#define PHYCLK_CLKSEL_48M (0x0 << 0)
+#define PHYCLK_CLKSEL_12M (0x2 << 0)
+#define PHYCLK_CLKSEL_24M (0x3 << 0)
+
+#define SAMSUNG_RSTCON (0x08)
+
+#define RSTCON_PHYLINK_SWRST (0x1 << 2)
+#define RSTCON_HLINK_SWRST (0x1 << 1)
+#define RSTCON_SWRST (0x1 << 0)
+/* EXYNOS5 */
+#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
+
+#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
+
+#define HOST_CTRL0_REFCLKSEL_MASK (0x3)
+#define HOST_CTRL0_REFCLKSEL(_x) ((_x) << 19)
+#define HOST_CTRL0_REFCLKSEL_XTAL \
+ HOST_CTRL0_REFCLKSEL(0x0)
+#define HOST_CTRL0_REFCLKSEL_EXTL \
+ HOST_CTRL0_REFCLKSEL(0x1)
+#define HOST_CTRL0_REFCLKSEL_CLKCORE \
+ HOST_CTRL0_REFCLKSEL(0x2)
+
+#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
+#define HOST_CTRL0_FSEL(_x) ((_x) << 16)
+#define HOST_CTRL0_FSEL_CLKSEL_50M (0x7)
+#define HOST_CTRL0_FSEL_CLKSEL_24M (0x5)
+#define HOST_CTRL0_FSEL_CLKSEL_20M (0x4)
+#define HOST_CTRL0_FSEL_CLKSEL_19200K (0x3)
+#define HOST_CTRL0_FSEL_CLKSEL_12M (0x2)
+#define HOST_CTRL0_FSEL_CLKSEL_10M (0x1)
+#define HOST_CTRL0_FSEL_CLKSEL_9600K (0x0)
+
+#define HOST_CTRL0_TESTBURNIN (0x1 << 11)
+#define HOST_CTRL0_RETENABLE (0x1 << 10)
+#define HOST_CTRL0_COMMONON_N (0x1 << 9)
+#define HOST_CTRL0_SIDDQ (0x1 << 6)
+#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
+#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
+#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
+#define HOST_CTRL0_UTMISWRST (0x1 << 2)
+#define HOST_CTRL0_LINKSWRST (0x1 << 1)
+#define HOST_CTRL0_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_TUNE0 (0x04)
+
+#define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
+
+#define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
+
+#define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
+
+#define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
+
+#define HSIC_CTRL_REFCLKSEL_MASK (0x3)
+#define HSIC_CTRL_REFCLKSEL (0x2 << 23)
+
+#define HSIC_CTRL_REFCLKDIV_MASK (0x7f)
+#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
+#define HSIC_CTRL_REFCLKDIV_12 \
+ HSIC_CTRL_REFCLKDIV(0x24)
+#define HSIC_CTRL_REFCLKDIV_15 \
+ HSIC_CTRL_REFCLKDIV(0x1C)
+#define HSIC_CTRL_REFCLKDIV_16 \
+ HSIC_CTRL_REFCLKDIV(0x1A)
+#define HSIC_CTRL_REFCLKDIV_19_2 \
+ HSIC_CTRL_REFCLKDIV(0x15)
+#define HSIC_CTRL_REFCLKDIV_20 \
+ HSIC_CTRL_REFCLKDIV(0x14)
+
+#define HSIC_CTRL_SIDDQ (0x1 << 6)
+#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
+#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
+#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
+#define HSIC_CTRL_UTMISWRST (0x1 << 2)
+#define HSIC_CTRL_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
+
+#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
+#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
+#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
+#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
+
+#define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
+
+#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
+#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
+#define HOST_OHCICTRL_CNTSEL (0x1 << 1)
+#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_SYS (0x38)
+
+#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
+#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
+#define OTG_SYS_PHY0_SWRST (0x1 << 12)
+
+#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
+#define OTG_SYS_REFCLKSEL(_x) ((_x) << 9)
+#define OTG_SYS_REFCLKSEL_XTAL \
+ OTG_SYS_REFCLKSEL(0x0)
+#define OTG_SYS_REFCLKSEL_EXTL \
+ OTG_SYS_REFCLKSEL(0x1)
+#define OTG_SYS_REFCLKSEL_CLKCORE \
+ OTG_SYS_REFCLKSEL(0x2)
+
+#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
+#define OTG_SYS_COMMON_ON (0x1 << 7)
+
+#define OTG_SYS_FSEL_MASK (0x7 << 4)
+#define OTG_SYS_FSEL(_x) ((_x) << 4)
+
+#define OTG_SYS_FORCESLEEP (0x1 << 3)
+#define OTG_SYS_OTGDISABLE (0x1 << 2)
+#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
+#define OTG_SYS_FORCESUSPEND (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_TUNE (0x40)
+
+/* USB 3.0: DRD */
+#define EXYNOS5_DRD_LINKSYSTEM (0x04)
+
+#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
+#define LINKSYSTEM_FLADJ(_x) ((_x) << 1)
+#define LINKSYSTEM_XHCI_VERSION_CONTROL (1 << 27)
+
+#define EXYNOS5_DRD_PHYUTMI (0x08)
+
+#define PHYUTMI_OTGDISABLE (1 << 6)
+#define PHYUTMI_FORCESUSPEND (1 << 1)
+#define PHYUTMI_FORCESLEEP (1 << 0)
+
+#define EXYNOS5_DRD_PHYPIPE (0x0C)
+
+#define EXYNOS5_DRD_PHYCLKRST (0x10)
+
+#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
+#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23)
+
+#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
+#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
+
+#define PHYCLKRST_SSC_EN (1 << 20)
+#define PHYCLKRST_REF_SSP_EN (1 << 19)
+#define PHYCLKRST_REF_CLKDIV2 (1 << 18)
+
+#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER(_x) ((_x) << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF \
+ PHYCLKRST_MPLL_MULTIPLIER(0x19)
+#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF \
+ PHYCLKRST_MPLL_MULTIPLIER(0x02)
+#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF \
+ PHYCLKRST_MPLL_MULTIPLIER(0x68)
+#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF \
+ PHYCLKRST_MPLL_MULTIPLIER(0x7d)
+#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF \
+ PHYCLKRST_MPLL_MULTIPLIER(0x02)
+
+#define PHYCLKRST_FSEL_MASK (0x3f << 5)
+#define PHYCLKRST_FSEL(_x) ((_x) << 5)
+#define PHYCLKRST_FSEL_PAD_100MHZ \
+ PHYCLKRST_FSEL(0x27)
+#define PHYCLKRST_FSEL_PAD_24MHZ \
+ PHYCLKRST_FSEL(0x2a)
+#define PHYCLKRST_FSEL_PAD_20MHZ \
++ PHYCLKRST_FSEL(0x31)
+#define PHYCLKRST_FSEL_PAD_19_2MHZ \
+ PHYCLKRST_FSEL(0x38)
+
+#define PHYCLKRST_RETENABLEN (1 << 4)
+
+#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
+#define PHYCLKRST_REFCLKSEL(_x) ((_x) << 2)
+#define PHYCLKRST_REFCLKSEL_PAD_REFCLK \
+ PHYCLKRST_REFCLKSEL(2)
+#define PHYCLKRST_REFCLKSEL_EXT_REFCLK \
+ PHYCLKRST_REFCLKSEL(3)
+
+#define PHYCLKRST_PORTRESET (1 << 1)
+#define PHYCLKRST_COMMONONN (1 << 0)
+
+#define EXYNOS5_DRD_PHYREG0 (0x14)
+#define EXYNOS5_DRD_PHYREG1 (0x18)
+
+#define EXYNOS5_DRD_PHYPARAM0 (0x1C)
+
+#define PHYPARAM0_REF_USE_PAD (0x1 << 31)
+#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
+#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
+
+#define EXYNOS5_DRD_PHYPARAM1 (0x20)
+
+#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH (0x1C)
+
+#define EXYNOS5_DRD_PHYTERM (0x24)
+
+#define EXYNOS5_DRD_PHYTEST (0x28)
+
+#define PHYTEST_POWERDOWN_SSP (1 << 3)
+#define PHYTEST_POWERDOWN_HSP (1 << 2)
+
+#define EXYNOS5_DRD_PHYADP (0x2C)
+
+#define EXYNOS5_DRD_PHYBATCHG (0x30)
+
+#define PHYBATCHG_UTMI_CLKSEL (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYRESUME (0x34)
+#define EXYNOS5_DRD_LINKPORT (0x44)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+ TYPE_S3C64XX,
+ TYPE_EXYNOS4210,
+ TYPE_EXYNOS5250,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @phy3: transceiver structure for USB 3.0
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @regs_phy3: usb 3.0 phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ * @phy_type: It keeps track of the PHY type.
+ * @host_usage: host_phy usage count.
+*/
+struct samsung_usbphy {
+ struct usb_phy phy;
+ struct usb_phy phy3;
+ struct samsung_usbphy_data *plat;
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *regs;
+ void __iomem *regs_phy3;
+ int ref_clk_freq;
+ int cpu_type;
+ enum samsung_usb_phy_type phy_type;
+ atomic_t host_usage;
+};
+
+#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
+#define phy3_to_sphy(x) container_of((x), struct samsung_usbphy, phy3)
+/*
++ * PHYs are different for USB Device and USB Host. Controllers can make
++ * sure that the correct PHY type is selected by calling this function
++ * before any PHY operation.
++ */
+int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type)
+{
+ struct samsung_usbphy *sphy = phy_to_sphy(phy);
+
+ if (sphy->phy_type != phy_type)
+ sphy->phy_type = phy_type;
+
+ return 0;
+}
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+ struct clk *ref_clk;
+ int refclk_freq = 0;
+
+ if (sphy->cpu_type == TYPE_EXYNOS5250)
+ ref_clk = clk_get(sphy->dev, "ext_xtal");
+ else
+ ref_clk = clk_get(sphy->dev, "xusbxti");
+ if (IS_ERR(ref_clk)) {
+ dev_err(sphy->dev, "Failed to get reference clock\n");
+ return PTR_ERR(ref_clk);
+ }
+ if (sphy->cpu_type == TYPE_EXYNOS5250) {
+ /* set clock frequency for PLL */
+ switch (clk_get_rate(ref_clk)) {
+ case 96 * 100000:
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_9600K;
+ break;
+ case 10 * MHZ:
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_10M;
+ break;
+ case 12 * MHZ:
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_12M;
+ break;
+ case 192 * 100000:
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_19200K;
+ break;
+ case 20 * MHZ:
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_20M;
+ break;
+ case 50 * MHZ:
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_50M;
+ break;
+ case 24 * MHZ:
+ default:
+ /* default reference clock */
+ refclk_freq |= HOST_CTRL0_FSEL_CLKSEL_24M;
+ }
+ } else {
+ switch (clk_get_rate(ref_clk)) {
+ case 12 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_24M;
+ break;
+ case 48 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_48M;
+ break;
+ default:
+ if (sphy->cpu_type == TYPE_S3C64XX)
+ refclk_freq = PHYCLK_CLKSEL_48M;
+ else
+ refclk_freq = PHYCLK_CLKSEL_24M;
+ break;
+ }
+ }
+ clk_put(ref_clk);
+
+ return refclk_freq;
+}
+
+ /*
+ * Sets the phy clk as EXTREFCLK (XXTI) which is internal clock form clock core.
+ */
+static u32 exynos5_usbphy3_set_clock(struct samsung_usbphy *sphy)
+{
+ u32 reg;
+ u32 refclk;
+
+ refclk = sphy->ref_clk_freq;
+
+ reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+ PHYCLKRST_FSEL(refclk);
+
+ switch (refclk) {
+ case HOST_CTRL0_FSEL_CLKSEL_50M:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x00));
+ break;
+ case HOST_CTRL0_FSEL_CLKSEL_20M:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x00));
+ break;
+ case HOST_CTRL0_FSEL_CLKSEL_19200K:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x88));
+ break;
+ case HOST_CTRL0_FSEL_CLKSEL_24M:
+ default:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x88));
+ break;
+ }
+
+ return reg;
+}
+
+static int exynos5_phyhost_is_on(void *regs)
+{
+ return (readl(regs + EXYNOS5_PHY_HOST_CTRL0) &
+ HOST_CTRL0_SIDDQ) ? 0 : 1;
+}
+
+static int samsung_exynos5_usbphy3_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs_phy3;
+ u32 phyparam0;
+ u32 phyparam1;
+ u32 linksystem;
+ u32 phybatchg;
+ u32 phytest;
+ u32 phyclkrst;
+ /* Reset USB 3.0 PHY */
+ writel(0x0, regs + EXYNOS5_DRD_PHYREG0);
+
+ phyparam0 = readl(regs + EXYNOS5_DRD_PHYPARAM0);
+ /* Select PHY CLK source */
+ phyparam0 &= ~PHYPARAM0_REF_USE_PAD;
+ /* Set Loss-of-Signal Detector sensitivity */
+ phyparam0 &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
+ phyparam0 |= PHYPARAM0_REF_LOSLEVEL;
+ writel(phyparam0, regs + EXYNOS5_DRD_PHYPARAM0);
+
+ writel(0x0, regs + EXYNOS5_DRD_PHYRESUME);
+
+ /*
+ * Setting the Frame length Adj value[6:1] to default 0x20
+ * See xHCI 1.0 spec, 5.2.4
+ */
+ linksystem = LINKSYSTEM_XHCI_VERSION_CONTROL |
+ LINKSYSTEM_FLADJ(0x20);
+ writel(linksystem, regs + EXYNOS5_DRD_LINKSYSTEM);
+
+ phyparam1 = readl(regs + EXYNOS5_DRD_PHYPARAM1);
+ /* Set Tx De-Emphasis level */
+ phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
+ phyparam1 |= PHYPARAM1_PCS_TXDEEMPH;
+ writel(phyparam1, regs + EXYNOS5_DRD_PHYPARAM1);
+
+ phybatchg = readl(regs + EXYNOS5_DRD_PHYBATCHG);
+ phybatchg |= PHYBATCHG_UTMI_CLKSEL;
+ writel(phybatchg, regs + EXYNOS5_DRD_PHYBATCHG);
+
+ /* PHYTEST POWERDOWN Control */
+ phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+ phytest &= ~(PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+ writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+
+ /* UTMI Power Control */
+ writel(PHYUTMI_OTGDISABLE, regs + EXYNOS5_DRD_PHYUTMI);
+
+ phyclkrst = exynos5_usbphy3_set_clock(sphy);
+
+ phyclkrst |= PHYCLKRST_PORTRESET |
+ /* Digital power supply in normal operating mode */
+ PHYCLKRST_RETENABLEN |
+ /* Enable ref clock for SS function */
+ PHYCLKRST_REF_SSP_EN |
+ /* Enable spread spectrum */
+ PHYCLKRST_SSC_EN |
+ /* Power down HS Bias and PLL blocks in suspend mode */
+ PHYCLKRST_COMMONONN;
+
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ udelay(10);
+
+ phyclkrst &= ~(PHYCLKRST_PORTRESET);
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ return 0;
+}
+
+static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyclk = sphy->ref_clk_freq;
+ u32 phyhost;
+ u32 phyotg;
+ u32 phyhsic;
+ u32 ehcictrl;
+ u32 ohcictrl;
+
+ atomic_inc(&sphy->host_usage);
+
+ if (exynos5_phyhost_is_on(regs)) {
+ dev_info(sphy->dev, "Already power on PHY\n");
+ return;
+ }
+ /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
+ if (sphy->plat && sphy->plat->phy_cfg_sel)
+ sphy->plat->phy_cfg_sel(sphy->dev, USB_PHY_TYPE_HOST);
+
+ /* Host configuration */
+ phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ /* phy reference clock configuration */
+ phyhost &= ~HOST_CTRL0_FSEL_MASK;
+ phyhost |= HOST_CTRL0_FSEL(phyclk);
+
+ /* host phy reset */
+ phyhost &= ~(HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL |
+ HOST_CTRL0_SIDDQ |
+ /* Enable normal mode of operation */
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP);
+
+ /* Link reset */
+ phyhost |= (HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST |
+ /* COMMON Block configuration during suspend */
+ HOST_CTRL0_COMMONON_N);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+ udelay(10);
+ phyhost &= ~(HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ /* OTG configuration */
+ phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+
+ /* phy reference clock configuration */
+ phyotg &= ~OTG_SYS_FSEL_MASK;
+ phyotg |= OTG_SYS_FSEL(phyclk);
+
+ /* Enable normal mode of operation */
+ phyotg &= ~(OTG_SYS_FORCESUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCESLEEP |
+ OTG_SYS_REFCLKSEL_MASK |
+ /* COMMON Block configuration during suspend */
+ OTG_SYS_COMMON_ON);
+
+ /* OTG phy & link reset */
+ phyotg |= (OTG_SYS_PHY0_SWRST |
+ OTG_SYS_LINKSWRST_UOTG |
+ OTG_SYS_PHYLINK_SWRESET |
+ OTG_SYS_OTGDISABLE |
+ /* Set phy refclk */
+ OTG_SYS_REFCLKSEL_CLKCORE);
+
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+ udelay(10);
+ phyotg &= ~(OTG_SYS_PHY0_SWRST |
+ OTG_SYS_LINKSWRST_UOTG |
+ OTG_SYS_PHYLINK_SWRESET);
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+
+ /* HSIC phy configuration */
+ phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+ HSIC_CTRL_REFCLKSEL |
+ HSIC_CTRL_PHYSWRST);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+ udelay(10);
+ phyhsic &= ~HSIC_CTRL_PHYSWRST;
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+ udelay(80);
+
+ /* enable EHCI DMA burst */
+ ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
+ ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
+ HOST_EHCICTRL_ENAINCR4 |
+ HOST_EHCICTRL_ENAINCR8 |
+ HOST_EHCICTRL_ENAINCR16);
+ writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
+
+ /* set ohci_suspend_on_n */
+ ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
+ ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
+ writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
+}
+
+static void samsung_exynos5_usbphy3_disable(struct samsung_usbphy *sphy)
+{
+ u32 phyutmi;
+ u32 phyclkrst;
+ u32 phytest;
+ void __iomem *regs = sphy->regs_phy3;
+
+ phyutmi = PHYUTMI_OTGDISABLE |
+ PHYUTMI_FORCESUSPEND |
+ PHYUTMI_FORCESLEEP;
+ writel(phyutmi, regs + EXYNOS5_DRD_PHYUTMI);
+
+ /* Resetting the PHYCLKRST enable bits to reduce leakage current */
+ phyclkrst = readl(regs + EXYNOS5_DRD_PHYCLKRST);
+ phyclkrst &= ~(PHYCLKRST_REF_SSP_EN |
+ PHYCLKRST_SSC_EN |
+ PHYCLKRST_COMMONONN);
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ /* Control PHYTEST to remove leakage current */
+ phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+ phytest |= (PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+ writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+}
+
+static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyhost;
+ u32 phyotg;
+ u32 phyhsic;
+
+ if (atomic_dec_return(&sphy->host_usage) > 0) {
+ dev_info(sphy->dev, "still being used\n");
+ return;
+ }
+
+ phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+ HSIC_CTRL_REFCLKSEL |
+ HSIC_CTRL_SIDDQ |
+ HSIC_CTRL_FORCESLEEP |
+ HSIC_CTRL_FORCESUSPEND);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+ phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+ phyhost |= (HOST_CTRL0_SIDDQ |
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP |
+ HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+ phyotg |= (OTG_SYS_FORCESUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCESLEEP);
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+}
+
+static int samsung_usbphy3_init(struct usb_phy *phy3)
+{
+ struct samsung_usbphy *sphy;
+ int ret = 0;
+
+ sphy = phy3_to_sphy(phy3);
+
+ if (sphy->cpu_type != TYPE_EXYNOS5250) {
+ dev_err(sphy->dev, "Not a valid cpu_type for USB 3.0\n");
+ return -ENODEV;
+ }
+ /* setting default phy-type for USB 3.0 */
+ samsung_usbphy_set_type(&sphy->phy3, USB_PHY_TYPE_DRD);
+
+ /* Enable the phy clock */
+ ret = clk_prepare_enable(sphy->clk);
+ if (ret) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return ret;
+ }
+
+ /* Disable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(false, sphy->phy_type);
+
+ /* Initialize usb phy registers */
+ samsung_exynos5_usbphy3_enable(sphy);
+
+ /* Disable the phy clock */
+ clk_disable_unprepare(sphy->clk);
+
+ return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy3_shutdown(struct usb_phy *phy3)
+{
+ struct samsung_usbphy *sphy;
+
+ sphy = phy3_to_sphy(phy3);
+
+ if (sphy->cpu_type != TYPE_EXYNOS5250) {
+ dev_err(sphy->dev, "Not a valid cpu_type for USB 3.0\n");
+ return;
+ }
+
+ /* setting default phy-type for USB 3.0 */
+ samsung_usbphy_set_type(&sphy->phy3, USB_PHY_TYPE_DRD);
+
+ if (clk_prepare_enable(sphy->clk)) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return;
+ }
+
+ /* De-initialize usb phy registers */
+ samsung_exynos5_usbphy3_disable(sphy);
+
+ /* Enable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(true, sphy->phy_type);
+
+ clk_disable_unprepare(sphy->clk);
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phypwr;
+ u32 phyclk;
+ u32 rstcon;
+
+ /* set clock frequency for PLL */
+ phyclk = sphy->ref_clk_freq;
+ phypwr = readl(regs + SAMSUNG_PHYPWR);
+ rstcon = readl(regs + SAMSUNG_RSTCON);
+
+ switch (sphy->cpu_type) {
+ case TYPE_S3C64XX:
+ phyclk &= ~PHYCLK_COMMON_ON_N;
+ phypwr &= ~PHYPWR_NORMAL_MASK;
+ rstcon |= RSTCON_SWRST;
+ break;
+ case TYPE_EXYNOS4210:
+ phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
+ rstcon |= RSTCON_SWRST;
+ default:
+ break;
+ }
+
+ writel(phyclk, regs + SAMSUNG_PHYCLK);
+ /* set to normal of PHY0 */
+ writel(phypwr, regs + SAMSUNG_PHYPWR);
+ /* reset all ports of PHY and Link */
+ writel(rstcon, regs + SAMSUNG_RSTCON);
+ udelay(10);
+ rstcon &= ~RSTCON_SWRST;
+ writel(rstcon, regs + SAMSUNG_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phypwr;
+
+ phypwr = readl(regs + SAMSUNG_PHYPWR);
+
+ switch (sphy->cpu_type) {
+ case TYPE_S3C64XX:
+ phypwr |= PHYPWR_NORMAL_MASK;
+ break;
+ case TYPE_EXYNOS4210:
+ phypwr |= PHYPWR_NORMAL_MASK_PHY0;
+ default:
+ break;
+ }
+
+ /* unset to normal of PHY0 */
+ writel(phypwr, regs + SAMSUNG_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ int ret = 0;
+
+ sphy = phy_to_sphy(phy);
+
+ /* Enable the phy clock */
+ ret = clk_prepare_enable(sphy->clk);
+ if (ret) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return ret;
+ }
+
+ /* Disable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(false, sphy->phy_type);
+
+ /* Initialize usb phy registers */
+ if (sphy->cpu_type == TYPE_EXYNOS5250)
+ samsung_exynos5_usbphy_enable(sphy);
+ else
+ samsung_usbphy_enable(sphy);
+ /* Disable the phy clock */
+ clk_disable_unprepare(sphy->clk);
+ return ret;
+}
+
+/*
++ * The function passed to the usb driver for phy shutdown
++ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+
+ sphy = phy_to_sphy(phy);
+
+ if (clk_prepare_enable(sphy->clk)) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return;
+ }
+
+ /* De-initialize usb phy registers */
+ if (sphy->cpu_type == TYPE_EXYNOS5250)
+ samsung_exynos5_usbphy_disable(sphy);
+ else
+ samsung_usbphy_disable(sphy);
+
+ /* Enable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(true, sphy->phy_type);
+
+ clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+ int data;
+ const struct of_device_id *match;
+ match = of_match_node(samsung_usbphy_dt_match,
+ pdev->dev.of_node);
+ data = (int) match->data;
+ return data;
+ }
+
+ return platform_get_device_id(pdev)->driver_data;
+}
+
+static int samsung_usbphy_probe(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy;
+ struct samsung_usbphy_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ void __iomem *phy_base;
+ struct resource *phy3_mem;
+ void __iomem *phy3_base = NULL;
+ struct clk *clk;
+ int ret = 0;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+ return -EINVAL;
+ }
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!phy_mem) {
+ dev_err(dev, "%s: missing mem resource\n", __func__);
+ return -ENODEV;
+ }
+
+ phy_base = devm_request_and_ioremap(dev, phy_mem);
+ if (!phy_base) {
+ dev_err(dev, "%s: register mapping failed\n", __func__);
+ return -ENXIO;
+ }
+
+ sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+ if (!sphy)
+ return -ENOMEM;
+
+ sphy->dev = &pdev->dev;
+ sphy->plat = pdata;
+ sphy->regs = phy_base;
+ sphy->phy.dev = sphy->dev;
+ sphy->phy.label = "samsung-usbphy";
+ sphy->phy.init = samsung_usbphy_init;
+ sphy->phy.shutdown = samsung_usbphy_shutdown;
+ sphy->cpu_type = samsung_usbphy_get_driver_data(pdev);
+ sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
+ platform_set_drvdata(pdev, sphy);
+
+ if (sphy->cpu_type == TYPE_EXYNOS5250)
+ clk = devm_clk_get(dev, "usbhost");
+ else
+ clk = devm_clk_get(dev, "otg");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get otg clock\n");
+ return PTR_ERR(clk);
+ }
+
+ sphy->clk = clk;
+
+ if (sphy->cpu_type == TYPE_EXYNOS5250) {
+ phy3_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!phy3_mem) {
+ dev_err(dev, "%s: missing mem resource\n", __func__);
+ return -ENODEV;
+ }
+ phy3_base = devm_request_and_ioremap(dev, phy3_mem);
+ if (!phy3_base) {
+ dev_err(dev, "%s: register mapping failed\n", __func__);
+ return -ENXIO;
+ }
+ }
+
+ sphy->regs_phy3 = phy3_base;
+ sphy->phy3.dev = sphy->dev;
+ sphy->phy3.label = "samsung-usbphy3";
+ sphy->phy3.init = samsung_usbphy3_init;
+ sphy->phy3.shutdown = samsung_usbphy3_shutdown;
+
+ ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+
+ if (ret)
+ return ret;
+
+ if (sphy->cpu_type != TYPE_EXYNOS5250) {
+ dev_warn(dev, "Not a valid cpu_type for USB 3.0\n");
+ } else {
+ ret = usb_add_phy(&sphy->phy3, USB_PHY_TYPE_USB3);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&sphy->phy);
+ if (sphy->cpu_type == TYPE_EXYNOS5250)
+ usb_remove_phy(&sphy->phy3);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+ {
+ .compatible = "samsung,s3c64xx-usbphy",
+ .data = (void *)TYPE_S3C64XX,
+ }, {
+ .compatible = "samsung,exynos4210-usbphy",
+ .data = (void *)TYPE_EXYNOS4210,
+ },{
+ .compatible = "samsung,exynos5250-usbphy",
+ .data = (void *)TYPE_EXYNOS5250,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+ {
+ .name = "s3c64xx-usbphy",
+ .driver_data = TYPE_S3C64XX,
+ }, {
+ .name = "exynos4210-usbphy",
+ .driver_data = TYPE_EXYNOS4210,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+ .probe = samsung_usbphy_probe,
+ .remove = samsung_usbphy_remove,
+ .id_table = samsung_usbphy_driver_ids,
+ .driver = {
+ //.name = "samsung-usbphy",
+ .name = "exynos5250-usbphy",
+ .owner = THIS_MODULE,
+ .of_match_table = samsung_usbphy_dt_match,
+ },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
index b50c38f8bc48..380ed95d0206 100644
--- a/include/linux/mfd/samsung/core.h
+++ b/include/linux/mfd/samsung/core.h
@@ -26,6 +26,7 @@ enum sec_device_type {
/**
* struct sec_pmic_dev - s5m87xx master device for sub-drivers
* @dev: master device of the chip (can be used to access platform data)
+ * @pdata: pointer to private data used to pass platform data to child
* @i2c: i2c client private data for regulator
* @rtc: i2c client private data for rtc
* @iolock: mutex for serializing io access
@@ -39,6 +40,7 @@ enum sec_device_type {
*/
struct sec_pmic_dev {
struct device *dev;
+ struct sec_platform_data *pdata;
struct regmap *regmap;
struct i2c_client *i2c;
struct i2c_client *rtc;
@@ -127,6 +129,7 @@ struct sec_platform_data {
struct sec_regulator_data {
int id;
struct regulator_init_data *initdata;
+ struct device_node *reg_node;
};
/*
diff --git a/include/linux/platform_data/exynos_thermal.h b/include/linux/platform_data/exynos_thermal.h
index a7bdb2f63b73..da7e6274b175 100644
--- a/include/linux/platform_data/exynos_thermal.h
+++ b/include/linux/platform_data/exynos_thermal.h
@@ -53,6 +53,8 @@ struct freq_clip_table {
* struct exynos_tmu_platform_data
* @threshold: basic temperature for generating interrupt
* 25 <= threshold <= 125 [unit: degree Celsius]
+ * @threshold_falling: differntial value for setting threshold
+ * of temperature falling interrupt.
* @trigger_levels: array for each interrupt levels
* [unit: degree Celsius]
* 0: temperature for trigger_level0 interrupt
@@ -97,6 +99,7 @@ struct freq_clip_table {
*/
struct exynos_tmu_platform_data {
u8 threshold;
+ u8 threshold_falling;
u8 trigger_levels[4];
bool trigger_level0_en;
bool trigger_level1_en;
diff --git a/include/linux/platform_data/samsung-usbphy.h b/include/linux/platform_data/samsung-usbphy.h
new file mode 100644
index 000000000000..52decfe36590
--- /dev/null
+++ b/include/linux/platform_data/samsung-usbphy.h
@@ -0,0 +1,29 @@
+/*
+copyright (C) 2012 Samsung Electronics Co.Ltd
+ * http://www.samsung.com/
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * 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.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ * @phy_cfg_sel: Function to control phy_cfg - Host/OTG.
+ */
+struct samsung_usbphy_data {
+ void (*pmu_isolation)(int on, int phy_type);
+ void (*phy_cfg_sel)(struct device *dev, int phy_type);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 90a8dfa9b6e9..3d5b4fcff687 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -74,6 +74,8 @@ enum thermal_trend {
THERMAL_TREND_STABLE, /* temperature is stable */
THERMAL_TREND_RAISING, /* temperature is raising */
THERMAL_TREND_DROPPING, /* temperature is dropping */
+ THERMAL_TREND_RAISE_FULL, /* Apply highest cooling action*/
+ THERMAL_TREND_DROP_FULL, /* Apply lowest cooling action*/
};
/* Events supported by Thermal Netlink */
diff --git a/include/linux/usb/samsung_usb_phy.h b/include/linux/usb/samsung_usb_phy.h
new file mode 100644
index 000000000000..bd6d900ef47e
--- /dev/null
+++ b/include/linux/usb/samsung_usb_phy.h
@@ -0,0 +1,29 @@
+/*
+ *copyright (C) 2012 Samsung Electronics Co.Ltd
+ * http://www.samsung.com/
+ *
+ * Defines phy types for samsung usb phy controllers - HOST or DEIVCE.
+ *
+ * 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/usb/phy.h>
+enum samsung_usb_phy_type
+{
+ USB_PHY_TYPE_DEVICE,
+ USB_PHY_TYPE_HOST,
+ USB_PHY_TYPE_DRD,
+};
+
+#ifdef CONFIG_SAMSUNG_USBPHY
+extern int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type);
+#else
+static inline int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type)
+{
+ return 0;
+}
+#endif /* CONFIG_SAMSUNG_USBPHY */