diff options
author | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-07-23 12:32:02 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-07-23 12:32:02 -0300 |
commit | bf8ebd444cd4780af7e031c1fc1ec5a1141bc9ab (patch) | |
tree | 2a5e77951748fe427be25cb7614df1373fdd35a3 | |
parent | 5d969334204ade2828ba6de4ccfa2e9ef3d4c893 (diff) | |
parent | 8cdf1a0d812974ed33868a4c74f62b8d128feff2 (diff) | |
download | linux-3.10-bf8ebd444cd4780af7e031c1fc1ec5a1141bc9ab.tar.gz linux-3.10-bf8ebd444cd4780af7e031c1fc1ec5a1141bc9ab.tar.bz2 linux-3.10-bf8ebd444cd4780af7e031c1fc1ec5a1141bc9ab.zip |
Merge remote-tracking branch 'tizen/tizen' into tizen-media-backports
* tizen/tizen: (119 commits)
arm: odroid: cpufreq: Support for frequency up to 1.7 GHz
cpufreq: BOOST: Adjust setting of BOOST frequency just before first valid freq
s5p-mfc: fix handling for MPEG2 decoding with IOMMU
arm: tizen_odroid_defconfig: enable pwm-fan driver
media: s5p_mfc: Check the right pointer after allocation
hwmon: pwm-fan: fix build error
dts: Enable pwm in Exynos4412-odroidu3 and add pwm-fan
hwmon: pwm-fan: Add pwm-fan driver
odroid: disable dmabuf-sync
media: s5p_mfc: remove unnecessary calling to function video_devdata()
arm: tizen_odroid_defconfig: enable MAX77686 RTC driver
ARM: dts: ODROID i2c improvements
ARM: dts: Enable PMIC interrupts on ODROID
ASoC: odroidx2_max98090: Rectify module device table name
ASoC: odroidx2_max98090: Move clock settings from ops to late_probe
ASoC: samsung-i2s: Maintain CDCLK settings across i2s_{shutdown/startup}
usbnet: smsc95xx: add reset_resume function with reset operation
usb: s3c-hsotg: break infinite loop in endpoint disable code
arm: tizen_odroid_defconfig: enable LED heartbeat
USB: add reset resume quirk for usb3503
...
Conflicts:
arch/arm/configs/tizen_odroid_defconfig
drivers/media/v4l2-core/videobuf2-core.c
79 files changed, 2901 insertions, 928 deletions
diff --git a/.gbs.conf b/.gbs.conf new file mode 100644 index 00000000000..2290232b08e --- /dev/null +++ b/.gbs.conf @@ -0,0 +1,3 @@ +[general] +upstream_branch = upstream +upstream_tag = v${upstreamversion} diff --git a/Documentation/cgroups/net_cls.txt b/Documentation/cgroups/net_cls.txt index 9face6bb578..ec182346dea 100644 --- a/Documentation/cgroups/net_cls.txt +++ b/Documentation/cgroups/net_cls.txt @@ -6,6 +6,8 @@ tag network packets with a class identifier (classid). The Traffic Controller (tc) can be used to assign different priorities to packets from different cgroups. +Also, Netfilter (iptables) can use this tag to perform +actions on such packets. Creating a net_cls cgroups instance creates a net_cls.classid file. This net_cls.classid value is initialized to 0. @@ -32,3 +34,6 @@ tc class add dev eth0 parent 10: classid 10:1 htb rate 40mbit - creating traffic class 10:1 tc filter add dev eth0 parent 10: protocol ip prio 10 handle 1: cgroup + +configuring iptables, basic example: +iptables -A OUTPUT -m cgroup ! --cgroup 0x100001 -j DROP diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt new file mode 100644 index 00000000000..610757ce449 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt @@ -0,0 +1,12 @@ +Bindings for a fan connected to the PWM lines + +Required properties: +- compatible : "pwm-fan" +- pwms : the PWM that is used to control the PWM fan + +Example: + pwm-fan { + compatible = "pwm-fan"; + status = "okay"; + pwms = <&pwm 0 10000 0>; + }; diff --git a/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt b/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt index 73a8914ea75..e4bb694398a 100644 --- a/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt +++ b/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt @@ -1,11 +1,24 @@ Samsung OdroidX2/U3 audio complex Required properties: - - compatible: - "samsung,odroidx2-audio" - for odroidx2 board - "samsung,odroidu3-audio" - for odroidu3 board - - samsung,i2s-controller: the phandle of the I2S controller - - samsung,audio-codec: the phandle of the max98090 audio codec + - compatible : "samsung,odroidx2-audio" - for odroidx2 board, + "samsung,odroidu3-audio" - for odroidu3 board + - samsung,model : the user-visible name of this sound complex. + - samsung,i2s-controller : the phandle of the I2S controller + - samsung,audio-codec : the phandle of the MAX98090 audio codec + - samsung,audio-routing : a list of the connections between audio + components; each entry is a pair of strings, the first being the + connection's sink, the second being the connection's source; + valid names for sources and sinks are the MAX98090's pins (as + documented in its binding), and the jacks on the board; + For Odroid X2: + * Headphone Jack + * Mic Jack + * DMIC + + For Odroid U3: + * Headphone Jack + * Speakers Example: @@ -14,4 +27,3 @@ sound { samsung,i2s-controller = <&i2s0>; samsung,audio-codec = <&max98090>; }; - diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt index 3070046da2e..0cda9146303 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt @@ -2,9 +2,10 @@ Required SoC Specific Properties: -- compatible : "samsung,i2s-v5" +- compatible: "samsung,i2s-v5" - reg: physical base address of the controller and length of memory mapped region. +- interrupts: should contain I2S interrupt number. - dmas: list of DMA controller phandle and DMA request line ordered pairs. - dma-names: identifier string for each DMA request line in the dmas property. These strings correspond 1:1 with the ordered pairs in dmas. @@ -16,7 +17,7 @@ Optional SoC Specific Properties: - samsung,supports-rstclr: This flag should be set if I2S software reset bit control is required. When this flag is set I2S software reset bit will be enabled or disabled based on need. -- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA, +- samsung,supports-secdai: If I2S block has a secondary FIFO and internal DMA, then this flag is enabled. - samsung,idma-addr: Internal DMA register base address of the audio sub system(used in secondary sound source). @@ -40,6 +41,7 @@ Example: i2s@03830000 { compatible = "samsung,i2s-v5"; reg = <0x03830000 0x100>; + interrupts = <0 97 0>; dmas = <&pdma0 10 &pdma0 9 &pdma0 8>; diff --git a/Documentation/devicetree/bindings/usb/exynos-usb.txt b/Documentation/devicetree/bindings/usb/exynos-usb.txt index b3abde73601..f7189b4cbce 100644 --- a/Documentation/devicetree/bindings/usb/exynos-usb.txt +++ b/Documentation/devicetree/bindings/usb/exynos-usb.txt @@ -38,6 +38,13 @@ Required properties: - interrupts: interrupt number to the cpu. - clocks: from common clock binding: handle to usb clock. - clock-names: from common clock binding: Shall be "usbhost". + - port: if in the SoC there are OHCI phys, they should be listed here. + One phy per port. Each port should have following entries: + - reg: port number on OHCI controller, e.g + On Exynos5250, port 0 is USB2.0 otg phy + port 1 is HSIC phy0 + port 2 is HSIC phy1 + - phys: from the *Generic PHY* bindings, specifying phy used by port. Example: usb@12120000 { @@ -47,4 +54,13 @@ Example: clocks = <&clock 285>; clock-names = "usbhost"; + + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + phys = <&usb2phy 1>; + status = "disabled"; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt index a018da4a7ad..221ac0dbc67 100644 --- a/Documentation/devicetree/bindings/usb/usb3503.txt +++ b/Documentation/devicetree/bindings/usb/usb3503.txt @@ -15,6 +15,14 @@ Optional properties: - reset-gpios: Should specify GPIO for reset. - initial-mode: Should specify initial mode. (1 for HUB mode, 2 for STANDBY mode) +- refclk: Clock used for driving REFCLK signal (optional, if not provided + the driver assumes that clock signal is always available, its + rate is specified by REF_SEL pins and a value from the primary + reference clock frequencies table is used) +- refclk-frequency: Frequency of the REFCLK signal as defined by REF_SEL + pins (optional, if not provided, driver will not set rate of the + REFCLK signal and assume that a value from the primary reference + clock frequencies table is used) Examples: usb3503@08 { diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt index 778838a0336..a67617acd07 100644 --- a/Documentation/devicetree/bindings/video/samsung-fimd.txt +++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt @@ -39,6 +39,49 @@ Required properties: Optional Properties: - samsung,power-domain: a phandle to FIMD power domain node. +- display-timings: timing settings for FIMD, as described in document [1]. + Can be used in case timings cannot be provided otherwise + or to override timings provided by the panel. +- samsung,sysreg: handle to syscon used to control the system registers +- i80-if-timings: timing configuration for lcd i80 interface support. + - cs-setup: clock cycles for the active period of address signal is enabled + until chip select is enabled. + If not specified, the default value(0) will be used. + - wr-setup: clock cycles for the active period of CS signal is enabled until + write signal is enabled. + If not specified, the default value(0) will be used. + - wr-active: clock cycles for the active period of CS is enabled. + If not specified, the default value(1) will be used. + - wr-hold: clock cycles for the active period of CS is disabled until write + signal is disabled. + If not specified, the default value(0) will be used. + + The parameters are defined as: + + VCLK(internal) __|¯¯¯¯¯¯|_____|¯¯¯¯¯¯|_____|¯¯¯¯¯¯|_____|¯¯¯¯¯¯|_____|¯¯ + : : : : : + Address Output --:<XXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XXXXXXXXXXXX:XX + | cs-setup+1 | : : : + |<---------->| : : : + Chip Select ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|____________:____________:____________|¯¯ + | wr-setup+1 | | wr-hold+1 | + |<---------->| |<---------->| + Write Enable ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|____________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ + | wr-active+1| + |<---------->| + Video Data ----------------------------<XXXXXXXXXXXXXXXXXXXXXXXXX>-- + +The device node can contain 'port' child nodes according to the bindings defined +in [2]. The following are properties specific to those nodes: +- reg: (required) port index, can be: + 0 - for CAMIF0 input, + 1 - for CAMIF1 input, + 2 - for CAMIF2 input, + 3 - for parallel output, + 4 - for write-back interface + +[1]: Documentation/devicetree/bindings/video/display-timing.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt Example: diff --git a/Documentation/hwmon/pwm-fan b/Documentation/hwmon/pwm-fan new file mode 100644 index 00000000000..18529d2e3bc --- /dev/null +++ b/Documentation/hwmon/pwm-fan @@ -0,0 +1,17 @@ +Kernel driver pwm-fan +===================== + +This driver enables the use of a PWM module to drive a fan. It uses the +generic PWM interface thus it is hardware independent. It can be used on +many SoCs, as long as the SoC supplies a PWM line driver that exposes +the generic PWM API. + +Author: Kamil Debski <k.debski@samsung.com> + +Description +----------- + +The driver implements a simple interface for driving a fan connected to +a PWM output. It uses the generic PWM interface, thus it can be used with +a range of SoCs. The driver exposes the fan to the user space through +the hwmon's sysfs interface. diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 931a5ad71e7..c227dac81d9 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -522,7 +522,7 @@ interrupts = <0 37 0>, <0 38 0>, <0 39 0>, <0 40 0>, <0 41 0>; clocks = <&clock 336>; clock-names = "timers"; - #pwm-cells = <2>; + #pwm-cells = <3>; samsung,pwm-outputs = <0>; status = "ok"; }; @@ -538,6 +538,25 @@ status = "disabled"; }; + ohci@12590000 { + compatible = "samsung,exynos4210-ohci"; + reg = <0x12590000 0x100>; + interrupts = <0 70 0>; + clocks = <&clock 304>; + clock-names = "usbhost"; + status = "disabled"; + + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + phys = <&exynos_usbphy 1>; + phy-names = "host"; + status = "disabled"; + }; + }; + ehci@12580000 { compatible = "samsung,exynos-ehci"; reg = <0x12580000 0x20000>; @@ -572,6 +591,7 @@ i2s0: i2s@03830000 { compatible = "samsung,i2s-v5"; reg = <0x03830000 0x100>; + interrupts = <0 97 0>; clocks = <&clock_audss 0>, <&clock_audss 3>, <&clock_audss 1>, <&clock_audss 2>, <&clock_audss 4>, <&clock_audss 2>; clock-names = "mout_audss", "mout_i2s", "dout_srp", diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 16000370198..86c54dcf3a8 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -48,7 +48,7 @@ status = "okay"; }; - sound { + sound: sound { compatible = "samsung,odroidx2-audio"; samsung,i2s-controller = <&i2s0>; samsung,audio-codec = <&max98090>; @@ -77,8 +77,10 @@ sdhci@12530000 { bus-width = <4>; - pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd_cdn>; pinctrl-names = "default"; + cd-gpios = <&gpk2 2 0>; + cd-inverted; status = "okay"; }; @@ -108,6 +110,8 @@ samsung,i2c-max-bus-freq = <100000>; pinctrl-0 = <&i2c0_bus>; pinctrl-names = "default"; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <400000>; status = "okay"; usb3503: usb3503@08 { @@ -123,6 +127,10 @@ max77686_pmic@09 { compatible = "maxim,max77686"; + interrupt-parent = <&gpx3>; + interrupts = <2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&max77686_irq>; reg = <0x09>; voltage-regulators { @@ -398,7 +406,6 @@ regulator-name = "VDD_BUCK8_2.8V"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; - regulator-always-on; }; buck9_reg: buck@9 { @@ -473,7 +480,7 @@ compatible = "maxim,max98090"; reg = <0x10>; interrupt-parent = <&gpx0>; - interrupts = <1 0>; + interrupts = <0 0>; }; }; @@ -493,10 +500,10 @@ }; cpufreq { - freq_table = <1400000 1300000 1200000 1100000 1000000 - 900000 800000 700000 600000 500000 400000 300000 - 200000>; - boost_freq = <1500000>; + freq_table = <1704000 1600000 1500000 1400000 1300000 1200000 + 1100000 1000000 900000 800000 700000 600000 + 500000 400000 300000 200000>; + boost_freq = <1800000>; vdd_arm-supply = <&buck2_reg>; status = "okay"; }; @@ -516,6 +523,29 @@ vdd_pll-supply = <&ldo8_reg>; status = "okay"; }; + + odroid_reboot { + pinctrl-names = "default"; + pinctrl-0 = <&emmc_ndet>; + compatible = "hardkernel,odroid-reboot"; + reset-gpio = <&gpk1 2 0>; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_power_key>; + + power_key { + interrupt-parent = <&gpx1>; + interrupts = <3 0>; + gpios = <&gpx1 3 1>; + linux,code = <116>; + label = "power key"; + debounce-interval = <10>; + gpio-key,wakeup; + }; + }; }; &pinctrl_1 { @@ -524,6 +554,18 @@ samsung,pin-pud = <0>; }; + max77686_irq: max77686-irq { + samsung,pins = "gpx3-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd_cdn: sd_cdn { + samsung,pins = "gpk2-2"; + samsung,pin-pud = <0>; + }; + gpio_home_key: home_key { samsung,pins = "gpx2-2"; samsung,pin-pud = <1>; @@ -533,4 +575,11 @@ samsung,pins = "gpx3-7"; samsung,pin-pud = <1>; }; + + emmc_ndet: emmc-ndet { + samsung,pins = "gpk1-2"; + samsung,pin-pud = <0>; + samsung,pin-con-pdn = <1>; + samsung,pin-pud-pdn = <0>; + }; }; diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts index 85ac5329cca..0bafd23f113 100644 --- a/arch/arm/boot/dts/exynos4412-odroidu3.dts +++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts @@ -19,7 +19,7 @@ compatible = "hardkernel,odroid-u3", "samsung,exynos4412", "samsung,exynos4"; memory { - reg = <0x40000000 0x40000000>; + reg = <0x40000000 0x7FF00000>; }; leds { @@ -31,11 +31,25 @@ linux,default-trigger = "heartbeat"; }; }; + + pwm: pwm@139D0000 { + pinctrl-0 = <&pwm0_out>; + pinctrl-names = "default"; + samsung,pwm-outputs = <0>; + status = "okay"; + }; + + pwm-fan { + compatible = "pwm-fan"; + status = "okay"; + pwms = <&pwm 0 10000 0>; + }; }; &usb3503 { clock-names = "refclk"; clocks = <&clock 21>; + refclk-frequency = <24000000>; }; &ehci { @@ -46,3 +60,15 @@ status = "okay"; }; }; + +&sound { + compatible = "samsung,odroidu3-audio"; + samsung,model = "Odroid-U3"; + samsung,audio-routing = + "Headphone Jack", "HPL", + "Headphone Jack", "HPR", + "Headphone Jack", "MICBIAS", + "IN1", "Headphone Jack", + "Speakers", "SPKL", + "Speakers", "SPKR"; +}; diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts index 53bc8bf7798..aed770fc767 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts @@ -19,7 +19,7 @@ compatible = "hardkernel,odroid-x", "samsung,exynos4412"; memory { - reg = <0x40000000 0x40000000>; + reg = <0x40000000 0x3FF00000>; }; leds { diff --git a/arch/arm/boot/dts/exynos4412-odroidx2.dts b/arch/arm/boot/dts/exynos4412-odroidx2.dts index 98166e5365f..c881c668bd7 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx2.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx2.dts @@ -19,7 +19,7 @@ compatible = "hardkernel,odroid-x2", "samsung,exynos4412", "samsung,exynos4"; memory { - reg = <0x40000000 0x40000000>; + reg = <0x40000000 0x7FF00000>; }; leds { @@ -39,20 +39,8 @@ }; gpio_keys { - compatible = "gpio-keys"; - pinctrl-names = "default"; pinctrl-0 = <&gpio_power_key &gpio_home_key>; - power_key { - interrupt-parent = <&gpx1>; - interrupts = <3 0>; - gpios = <&gpx1 3 1>; - linux,code = <116>; - label = "power key"; - debounce-interval = <10>; - gpio-key,wakeup; - }; - home_key { interrupt-parent = <&gpx2>; interrupts = <2 0>; @@ -86,6 +74,7 @@ &usb3503 { clock-names = "refclk"; clocks = <&usbhubxti>; + refclk-frequency = <26000000>; }; &ehci { @@ -93,3 +82,12 @@ status = "okay"; }; }; + +&sound { + samsung,model = "Odroid-X2"; + samsung,audio-routing = + "Headphone Jack", "HPL", + "Headphone Jack", "HPR", + "IN1", "Mic Jack", + "Mic Jack", "MICBIAS"; +}; diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 219687ca92d..944c57469f0 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -1046,6 +1046,9 @@ vddcore-supply = <&ldo8_reg>; vddio-supply = <&ldo10_reg>; samsung,pll-clock-frequency = <24000000>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; ports { @@ -1130,10 +1133,21 @@ extcon = <&max_muic>; }; + ohci@12590000 { + status = "okay"; + port@0 { + status = "okay"; + }; + }; + ehci@12580000 { status = "okay"; vusb_d-supply = <&ldo15_reg>; vusb_a-supply = <&ldo12_reg>; + samsung,vbus-gpio = <&gpf0 7 0>; + port@0 { + status = "okay"; + }; port@1 { status = "okay"; }; @@ -1278,7 +1292,7 @@ }; sound { - compatible = "samsung,exynos4-wm1811"; + compatible = "samsung,trats2-wm1811"; clocks = <&clock 2>, <&clock 396>, <&clock 21>, <&clock 6>; clock-names = "parent", "out-mux", "out", "pll" /* EPLL */; samsung,i2s-controller = <&i2s0>; @@ -1294,9 +1308,9 @@ }; cpufreq { - freq_table = <1400000 1300000 1200000 1100000 1000000 - 900000 800000 700000 600000 500000 400000 300000 - 200000>; + freq_table = <1400000 1300000 1200000 1100000 1000000 900000 + 800000 700000 600000 500000 400000 300000 + 200000>; boost_freq = <1500000>; lab-num-of-states = <5>; lab-ctrl-freq = < 0 0 0 1300000 1200000 diff --git a/arch/arm/configs/tizen_defconfig b/arch/arm/configs/tizen_defconfig index 2b38f7c9f0a..701aa167549 100644 --- a/arch/arm/configs/tizen_defconfig +++ b/arch/arm/configs/tizen_defconfig @@ -2402,20 +2402,17 @@ CONFIG_SND_SOC=y # CONFIG_SND_ATMEL_SOC is not set # CONFIG_SND_DESIGNWARE_I2S is not set CONFIG_SND_SOC_SAMSUNG=y -CONFIG_SND_SAMSUNG_PCM=y -CONFIG_SND_SAMSUNG_SPDIF=y CONFIG_SND_SAMSUNG_I2S=y -CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=y +# CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994 is not set # CONFIG_SND_SAMSUNG_I2S_MASTER is not set -CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF=y -CONFIG_SND_SOC_SMDK_WM8994_PCM=y +# CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF is not set +# CONFIG_SND_SOC_SMDK_WM8994_PCM is not set CONFIG_SND_SOC_TRATS=y -CONFIG_SND_SOC_SAMSUNG_EXYNOS4_WM1811=y +CONFIG_SND_SOC_SAMSUNG_TRATS2_WM1811=y # CONFIG_SND_SOC_ODROIDX2 is not set CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set CONFIG_SND_SOC_WM_HUBS=y -CONFIG_SND_SOC_SPDIF=y CONFIG_SND_SOC_WM8994=y CONFIG_SND_SOC_MC1N2=y CONFIG_SND_SOC_USE_EXTERNAL_MIC_BIAS=y diff --git a/arch/arm/configs/tizen_odroid_defconfig b/arch/arm/configs/tizen_odroid_defconfig index 06348d21b7e..1aee7a961cd 100755..100644 --- a/arch/arm/configs/tizen_odroid_defconfig +++ b/arch/arm/configs/tizen_odroid_defconfig @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 3.10.33 Kernel Configuration +# Linux/arm 3.10.39 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -402,8 +402,11 @@ CONFIG_SWP_EMULATE=y # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y -# CONFIG_CACHE_L2X0 is not set +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y CONFIG_ARM_L1_CACHE_SHIFT_6=y CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_DMA_MEM_BUFFERABLE=y @@ -414,13 +417,17 @@ CONFIG_MULTI_IRQ_HANDLER=y # CONFIG_ARM_ERRATA_460075 is not set # CONFIG_ARM_ERRATA_742230 is not set # CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set # CONFIG_ARM_ERRATA_643719 is not set # CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set # CONFIG_ARM_ERRATA_743622 is not set # CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set # CONFIG_ARM_ERRATA_754322 is not set # CONFIG_ARM_ERRATA_754327 is not set # CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set # CONFIG_ARM_ERRATA_775420 is not set # CONFIG_ARM_ERRATA_798181 is not set @@ -610,27 +617,36 @@ CONFIG_UNIX=y # CONFIG_UNIX_DIAG is not set CONFIG_XFRM=y CONFIG_XFRM_ALGO=y -# CONFIG_XFRM_USER is not set +CONFIG_XFRM_USER=y # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set # CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y CONFIG_NET_KEY=y # CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE_DEMUX is not set -# CONFIG_NET_IP_TUNNEL is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_IP_MROUTE is not set # CONFIG_ARPD is not set # CONFIG_SYN_COOKIES is not set # CONFIG_NET_IPVTI is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_XFRM_MODE_BEET=y @@ -638,42 +654,266 @@ CONFIG_INET_LRO=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_INET_UDP_DIAG is not set -# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=y CONFIG_TCP_CONG_CUBIC=y -CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +CONFIG_DEFAULT_BIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="bic" # CONFIG_TCP_MD5SIG is not set CONFIG_IPV6=y -# CONFIG_IPV6_PRIVACY is not set -# CONFIG_IPV6_ROUTER_PREF is not set -# CONFIG_IPV6_OPTIMISTIC_DAD is not set -# CONFIG_INET6_AH is not set -# CONFIG_INET6_ESP is not set -# CONFIG_INET6_IPCOMP is not set -# CONFIG_IPV6_MIP6 is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set -# CONFIG_IPV6_SIT is not set -# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y # CONFIG_IPV6_GRE is not set -# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MROUTE is not set +CONFIG_NETLABEL=y # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETWORK_PHY_TIMESTAMPING is not set -# CONFIG_NETFILTER is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_NF_NAT_TFTP=y +# CONFIG_NETFILTER_TPROXY is not set +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +# CONFIG_IP_NF_SECURITY is not set +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_NF_NAT_IPV6 is not set +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set # CONFIG_RDS is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_L2TP is not set -# CONFIG_BRIDGE is not set +CONFIG_STP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y CONFIG_HAVE_NET_DSA=y # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set +CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -681,7 +921,67 @@ CONFIG_HAVE_NET_DSA=y # CONFIG_LAPB is not set # CONFIG_PHONET is not set # CONFIG_IEEE802154 is not set -# CONFIG_NET_SCHED is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_CGROUP=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y # CONFIG_DCB is not set CONFIG_DNS_RESOLVER=y # CONFIG_BATMAN_ADV is not set @@ -705,6 +1005,7 @@ CONFIG_BQL=y # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y CONFIG_WIRELESS=y # CONFIG_CFG80211 is not set # CONFIG_LIB80211 is not set @@ -747,7 +1048,7 @@ CONFIG_REGMAP_SPI=y CONFIG_REGMAP_MMIO=y CONFIG_REGMAP_IRQ=y CONFIG_DMA_SHARED_BUFFER=y -CONFIG_DMABUF_SYNC=y +# CONFIG_DMABUF_SYNC is not set CONFIG_CMA=y CONFIG_CMA_DEBUG=y @@ -825,7 +1126,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 # CONFIG_BMP085_SPI is not set # CONFIG_USB_SWITCH_FSA9480 is not set # CONFIG_LATTICE_ECP3_CONFIG is not set -# CONFIG_SLP_GLOBAL_LOCK is not set +CONFIG_SLP_GLOBAL_LOCK=y # CONFIG_SRAM is not set # CONFIG_SII9234 is not set # CONFIG_C2PORT is not set @@ -922,6 +1223,7 @@ CONFIG_NET_CORE=y # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set CONFIG_MII=y +# CONFIG_IFB is not set # CONFIG_NET_TEAM is not set # CONFIG_MACVLAN is not set # CONFIG_VXLAN is not set @@ -1095,6 +1397,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_TCA6416 is not set # CONFIG_KEYBOARD_TCA8418 is not set # CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set # CONFIG_KEYBOARD_LM8333 is not set # CONFIG_KEYBOARD_MAX7359 is not set # CONFIG_KEYBOARD_MCS is not set @@ -1397,7 +1700,111 @@ CONFIG_DEBUG_GPIO=y # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_POWER_AVS is not set -# CONFIG_HWMON is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +CONFIG_SENSORS_PWM_FAN=y +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # CONFIG_THERMAL is not set # CONFIG_WATCHDOG is not set CONFIG_SSB_POSSIBLE=y @@ -1682,6 +2089,7 @@ CONFIG_VIDEO_TVEEPROM=y # CONFIG_MEDIA_SUBDRV_AUTOSELECT=y CONFIG_MEDIA_ATTACH=y +CONFIG_VIDEO_IR_I2C=y # # Audio decoders, processors and mixers @@ -1723,7 +2131,11 @@ CONFIG_MEDIA_ATTACH=y # Sensors used on soc_camera driver # CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_MT2060=y +CONFIG_MEDIA_TUNER_MT2266=y +CONFIG_MEDIA_TUNER_XC2028=y CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y CONFIG_MEDIA_TUNER_MXL5007T=y # @@ -1741,6 +2153,9 @@ CONFIG_MEDIA_TUNER_MXL5007T=y # # DVB-T (terrestrial) frontends # +CONFIG_DVB_DIB3000MC=y +CONFIG_DVB_DIB7000M=y +CONFIG_DVB_DIB7000P=y # # DVB-C (cable) frontends @@ -1754,14 +2169,18 @@ CONFIG_DVB_LG2160=y CONFIG_DVB_AU8522=y CONFIG_DVB_AU8522_DTV=y CONFIG_DVB_AU8522_V4L=y +CONFIG_DVB_S5H1411=y # # ISDB-T (terrestrial) frontends # +CONFIG_DVB_DIB8000=y # # Digital terrestrial only tuners/PLL # +CONFIG_DVB_TUNER_DIB0070=y +CONFIG_DVB_TUNER_DIB0090=y # # SEC control devices for DVB-S @@ -1914,6 +2333,8 @@ CONFIG_SND_USB_AUDIO=m # CONFIG_SND_USB_CAIAQ is not set # CONFIG_SND_USB_6FIRE is not set CONFIG_SND_SOC=y +CONFIG_SND_SOC_DMAENGINE_PCM=y +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y # CONFIG_SND_ATMEL_SOC is not set # CONFIG_SND_DESIGNWARE_I2S is not set CONFIG_SND_SOC_SAMSUNG=y @@ -1923,7 +2344,7 @@ CONFIG_SND_SAMSUNG_I2S_MASTER=y # CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF is not set # CONFIG_SND_SOC_SMDK_WM8994_PCM is not set # CONFIG_SND_SOC_TRATS is not set -# CONFIG_SND_SOC_SAMSUNG_EXYNOS4_WM1811 is not set +# CONFIG_SND_SOC_SAMSUNG_TRATS2_WM1811 is not set CONFIG_SND_SOC_ODROIDX2=y CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set @@ -1996,7 +2417,10 @@ CONFIG_HID_MONTEREY=y # CONFIG_HID_SMARTJOYPLUS is not set # CONFIG_HID_TIVO is not set # CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THINGM is not set # CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WIIMOTE is not set # CONFIG_HID_ZEROPLUS is not set # CONFIG_HID_ZYDACRON is not set # CONFIG_HID_SENSOR_HUB is not set @@ -2123,9 +2547,8 @@ CONFIG_USB_PHY=y # CONFIG_NOP_USB_XCEIV is not set # CONFIG_OMAP_CONTROL_USB is not set # CONFIG_OMAP_USB3 is not set -CONFIG_SAMSUNG_USBPHY=y -CONFIG_SAMSUNG_USB2PHY=y -CONFIG_SAMSUNG_USB3PHY=y +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set # CONFIG_USB_GPIO_VBUS is not set # CONFIG_USB_ISP1301 is not set # CONFIG_USB_RCAR_PHY is not set @@ -2150,16 +2573,12 @@ CONFIG_USB_S3C_HSOTG=y # CONFIG_USB_NET2272 is not set # CONFIG_USB_DUMMY_HCD is not set CONFIG_USB_LIBCOMPOSITE=y -CONFIG_USB_U_ETHER=y -CONFIG_USB_F_ECM=y -CONFIG_USB_F_SUBSET=y -CONFIG_USB_F_RNDIS=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y # CONFIG_USB_CONFIGFS is not set # CONFIG_USB_ZERO is not set # CONFIG_USB_AUDIO is not set -CONFIG_USB_ETH=y -CONFIG_USB_ETH_RNDIS=y -# CONFIG_USB_ETH_EEM is not set +# CONFIG_USB_ETH is not set # CONFIG_USB_G_NCM is not set # CONFIG_USB_GADGETFS is not set # CONFIG_USB_FUNCTIONFS is not set @@ -2167,7 +2586,7 @@ CONFIG_USB_ETH_RNDIS=y # CONFIG_USB_G_SERIAL is not set # CONFIG_USB_MIDI_GADGET is not set # CONFIG_USB_G_PRINTER is not set -# CONFIG_USB_G_SLP is not set +CONFIG_USB_G_SLP=y # CONFIG_USB_CDC_COMPOSITE is not set # CONFIG_USB_G_ACM_MS is not set # CONFIG_USB_G_MULTI is not set @@ -2176,7 +2595,7 @@ CONFIG_USB_ETH_RNDIS=y # CONFIG_USB_G_WEBCAM is not set CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set -# CONFIG_MMC_UNSAFE_RESUME is not set +CONFIG_MMC_UNSAFE_RESUME=y # CONFIG_MMC_CLKGATE is not set # @@ -2205,7 +2624,51 @@ CONFIG_MMC_DW_EXYNOS=y # CONFIG_MMC_VUB300 is not set # CONFIG_MMC_USHC is not set # CONFIG_MEMSTICK is not set -# CONFIG_NEW_LEDS is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_MAX8997 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set # CONFIG_ACCESSIBILITY is not set # CONFIG_EDAC is not set CONFIG_RTC_LIB=y @@ -2233,7 +2696,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_DS3232 is not set # CONFIG_RTC_DRV_MAX6900 is not set # CONFIG_RTC_DRV_MAX8997 is not set -# CONFIG_RTC_DRV_MAX77686 is not set +CONFIG_RTC_DRV_MAX77686=y # CONFIG_RTC_DRV_RS5C372 is not set # CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_ISL12022 is not set @@ -2403,7 +2866,9 @@ CONFIG_EXYNOS_IOMMU=y # CONFIG_EXTCON is not set # CONFIG_MEMORY is not set # CONFIG_IIO is not set -# CONFIG_PWM is not set +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +CONFIG_PWM_SAMSUNG=y CONFIG_IRQCHIP=y CONFIG_ARM_GIC=y CONFIG_GIC_NON_BANKED=y @@ -2415,10 +2880,10 @@ CONFIG_GIC_NON_BANKED=y # CONFIG_GENERIC_PHY=y # CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +CONFIG_EXYNOS_PHY=y CONFIG_PHY_SAMSUNG_USB2=y CONFIG_PHY_EXYNOS4210_USB2=y CONFIG_PHY_EXYNOS4X12_USB2=y -CONFIG_EXYNOS_PHY=y # # File systems @@ -2433,8 +2898,8 @@ CONFIG_EXT3_FS_XATTR=y # CONFIG_EXT3_FS_POSIX_ACL is not set # CONFIG_EXT3_FS_SECURITY is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_POSIX_ACL is not set -# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y # CONFIG_EXT4_DEBUG is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set @@ -2453,10 +2918,11 @@ CONFIG_FILE_LOCKING=y CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY_USER=y -# CONFIG_FANOTIFY is not set +CONFIG_FANOTIFY=y +# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set # CONFIG_QUOTA is not set # CONFIG_QUOTACTL is not set -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set CONFIG_GENERIC_ACL=y @@ -2526,6 +2992,7 @@ CONFIG_NFS_V3=y CONFIG_NFS_V4=y # CONFIG_NFS_SWAP is not set # CONFIG_NFS_V4_1 is not set +# CONFIG_ROOT_NFS is not set # CONFIG_NFS_USE_LEGACY_DNS is not set CONFIG_NFS_USE_KERNEL_DNS=y # CONFIG_NFSD is not set @@ -2728,10 +3195,20 @@ CONFIG_KEYS=y # CONFIG_ENCRYPTED_KEYS is not set # CONFIG_KEYS_DEBUG_PROC_KEYS is not set # CONFIG_SECURITY_DMESG_RESTRICT is not set -# CONFIG_SECURITY is not set +CONFIG_SECURITY=y CONFIG_SECURITYFS=y -CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_DEFAULT_SECURITY="" +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_SECURITY_SMACK=y +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SMACK=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="smack" CONFIG_CRYPTO=y # @@ -2739,6 +3216,7 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_AEAD2=y CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_BLKCIPHER2=y @@ -2756,7 +3234,7 @@ CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y # CONFIG_CRYPTO_PCRYPT is not set CONFIG_CRYPTO_WORKQUEUE=y # CONFIG_CRYPTO_CRYPTD is not set -# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_AUTHENC=y # CONFIG_CRYPTO_TEST is not set # @@ -2781,7 +3259,7 @@ CONFIG_CRYPTO_CBC=y # Hash modes # # CONFIG_CRYPTO_CMAC is not set -# CONFIG_CRYPTO_HMAC is not set +CONFIG_CRYPTO_HMAC=y # CONFIG_CRYPTO_XCBC is not set # CONFIG_CRYPTO_VMAC is not set @@ -2792,13 +3270,13 @@ CONFIG_CRYPTO_CRC32C=y # CONFIG_CRYPTO_CRC32 is not set # CONFIG_CRYPTO_GHASH is not set # CONFIG_CRYPTO_MD4 is not set -# CONFIG_CRYPTO_MD5 is not set +CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_RMD128 is not set # CONFIG_CRYPTO_RMD160 is not set # CONFIG_CRYPTO_RMD256 is not set # CONFIG_CRYPTO_RMD320 is not set -# CONFIG_CRYPTO_SHA1 is not set +CONFIG_CRYPTO_SHA1=y # CONFIG_CRYPTO_SHA1_ARM is not set CONFIG_CRYPTO_SHA256=y # CONFIG_CRYPTO_SHA512 is not set @@ -2816,7 +3294,7 @@ CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_DES is not set +CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_FCRYPT is not set # CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_SALSA20 is not set @@ -2828,7 +3306,7 @@ CONFIG_CRYPTO_AES=y # # Compression # -# CONFIG_CRYPTO_DEFLATE is not set +CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set @@ -2861,9 +3339,10 @@ CONFIG_CRC32_SLICEBY8=y # CONFIG_CRC32_SARWATE is not set # CONFIG_CRC32_BIT is not set # CONFIG_CRC7 is not set -# CONFIG_LIBCRC32C is not set +CONFIG_LIBCRC32C=y # CONFIG_CRC8 is not set CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y CONFIG_LZO_COMPRESS=y CONFIG_LZO_DECOMPRESS=y CONFIG_XZ_DEC=y @@ -2880,6 +3359,10 @@ CONFIG_DECOMPRESS_BZIP2=y CONFIG_DECOMPRESS_LZMA=y CONFIG_DECOMPRESS_XZ=y CONFIG_DECOMPRESS_LZO=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y CONFIG_HAS_IOMEM=y CONFIG_HAS_DMA=y CONFIG_CPU_RMAP=y diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 0b539ea1bda..9f6844cf498 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o obj-$(CONFIG_MACH_EXYNOS5_DT) += mach-exynos5-dt.o obj-$(CONFIG_ARCH_EXYNOS4) += sec-reboot.o +obj-$(CONFIG_ARCH_EXYNOS4) += odroid-reboot.o # device support diff --git a/arch/arm/mach-exynos/odroid-reboot.c b/arch/arm/mach-exynos/odroid-reboot.c new file mode 100644 index 00000000000..a81a5cb863a --- /dev/null +++ b/arch/arm/mach-exynos/odroid-reboot.c @@ -0,0 +1,96 @@ +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <asm/cacheflush.h> +#include <asm/system.h> +#include <mach/regs-pmu.h> +#include <linux/gpio.h> +#include "common.h" +#include <linux/extcon.h> +#include <linux/of.h> +#include <linux/of_gpio.h> + +struct odroid_reboot_platform_data { + struct device *dev; + int power_gpio; +}; + +static struct odroid_reboot_platform_data *g_pdata; + +static void odroid_reboot(char str, const char *cmd) +{ + local_irq_disable(); + + writel(0x12345678, S5P_INFORM2); /* Don't enter lpm mode */ + writel(0x0, S5P_INFORM4); /* Reset reboot count */ + + gpio_set_value(g_pdata->power_gpio, 0); + mdelay(150); + gpio_set_value(g_pdata->power_gpio, 1); + + flush_cache_all(); + outer_flush_all(); + + exynos4_restart(0, 0); + + pr_emerg("%s: waiting for reboot\n", __func__); + while (1) + ; +} + +static struct odroid_reboot_platform_data *odroid_reboot_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct odroid_reboot_platform_data *pdata; + + pdata = devm_kzalloc(dev, sizeof(struct odroid_reboot_platform_data), + GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->power_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (!gpio_is_valid(pdata->power_gpio)) { + dev_err(dev, "invalied power-gpio\n"); + return NULL; + } + devm_gpio_request(dev, pdata->power_gpio, "reset-gpio"); + + return pdata; +} + +static int odroid_reboot_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + if (pdev->dev.of_node) + g_pdata = odroid_reboot_parse_dt(dev); + + if (!g_pdata) { + dev_err(&pdev->dev, "failed to get platform data\n"); + return -EINVAL; + } + + g_pdata->dev = &pdev->dev; + + /* Set machine specific functions */ + arm_pm_restart = odroid_reboot; + + return 0; +} + +static struct of_device_id odroid_reboot_of_match[] = { + { .compatible = "hardkernel,odroid-reboot", }, + { }, +}; + +static struct platform_driver odroid_reboot_driver = { + .probe = odroid_reboot_probe, + .driver = { + .name = "odroid-reboot", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(odroid_reboot_of_match), + } +}; + +module_platform_driver(odroid_reboot_driver); diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c index ec0d731b0e7..011f232f6f3 100644 --- a/arch/arm/plat-samsung/dma-ops.c +++ b/arch/arm/plat-samsung/dma-ops.c @@ -122,6 +122,16 @@ static inline int samsung_dmadev_flush(unsigned ch) return dmaengine_terminate_all((struct dma_chan *)ch); } +static inline int samsung_dmadev_pause(unsigned ch) +{ + return dmaengine_pause((struct dma_chan *)ch); +} + +static inline int samsung_dmadev_resume(unsigned ch) +{ + return dmaengine_resume((struct dma_chan *)ch); +} + static struct samsung_dma_ops dmadev_ops = { .request = samsung_dmadev_request, .release = samsung_dmadev_release, @@ -131,6 +141,8 @@ static struct samsung_dma_ops dmadev_ops = { .started = NULL, .flush = samsung_dmadev_flush, .stop = samsung_dmadev_flush, + .pause = samsung_dmadev_pause, + .resume = samsung_dmadev_resume, }; void *samsung_dmadev_get_ops(void) diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h index ce6d7634b6c..9e14fe001e2 100644 --- a/arch/arm/plat-samsung/include/plat/dma-ops.h +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h @@ -47,6 +47,8 @@ struct samsung_dma_ops { int (*started)(unsigned ch); int (*flush)(unsigned ch); int (*stop)(unsigned ch); + int (*pause)(unsigned ch); + int (*resume)(unsigned ch); }; extern void *samsung_dmadev_get_ops(void); diff --git a/drivers/clk/samsung/clk-exynos4-audss.c b/drivers/clk/samsung/clk-exynos4-audss.c index 4522d000a5b..28c18d03ef9 100644 --- a/drivers/clk/samsung/clk-exynos4-audss.c +++ b/drivers/clk/samsung/clk-exynos4-audss.c @@ -51,22 +51,36 @@ static struct clk_onecell_data clk_data; static void __iomem *io_base; static struct clk *clks[AUDSS_CLK_MAX]; +#ifdef CONFIG_PM_SLEEP +static unsigned long reg_save[][2] = { + { AUDSS_CLKSRC, 0 }, + { AUDSS_CLKDIV, 0 }, + { AUDSS_CLKGATE, 0 }, +}; + static int samsung_audss_clk_suspend(void) { - /* TODO: */ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg_save); i++) + reg_save[i][1] = readl(io_base + reg_save[i][0]); + return 0; } static void samsung_audss_clk_resume(void) { - /* TODO: */ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg_save); i++) + writel(reg_save[i][1], io_base + reg_save[i][0]); } static struct syscore_ops samsung_audss_clk_syscore_ops = { .suspend = samsung_audss_clk_suspend, .resume = samsung_audss_clk_resume, }; - +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_OF static struct of_device_id audss_of_match[] __initdata = { diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index a3ba9396760..e37793ededd 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1034,6 +1034,9 @@ static DEFINE_SPINLOCK(clkout_lock); /* PLLs PMS values */ struct pll_pms pll35xx_exynos4412_pms[] = { + {.p = 4, .m = 300, .s = 0}, + {.p = 3, .m = 213, .s = 0}, + {.p = 3, .m = 200, .s = 0}, {.p = 4, .m = 250, .s = 0}, {.p = 3, .m = 175, .s = 0}, {.p = 6, .m = 325, .s = 0}, diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 0ecb7c918ce..feda2e5fcdd 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -293,7 +293,7 @@ int exynos_of_parse_boost(struct exynos_dvfs_info *info, { struct cpufreq_frequency_table *ft = info->freq_table; struct device_node *node = info->dev->of_node; - unsigned int boost_freq; + unsigned int boost_freq, i; if (of_property_read_u32(node, property_name, &boost_freq)) { pr_err("%s: Property: %s not found\n", __func__, @@ -310,10 +310,19 @@ int exynos_of_parse_boost(struct exynos_dvfs_info *info, * frequency table is required. */ - ft[0].index = CPUFREQ_BOOST_FREQ; - ft[0].frequency = boost_freq; + for (i = 0; ft[i].frequency != CPUFREQ_TABLE_END; i++) + if (ft[i].frequency != CPUFREQ_ENTRY_INVALID) + break; - pr_debug("%s: BOOST frequency: %d\n", __func__, ft[0].frequency); + if (--i >= 0) { + ft[i].index = CPUFREQ_BOOST_FREQ; + ft[i].frequency = boost_freq; + } else { + pr_err("%s: BOOST index: %d out of range\n", __func__, i); + return -EINVAL; + } + + pr_debug("%s: BOOST frequency: %d\n", __func__, ft[i].frequency); return 0; } @@ -323,8 +332,8 @@ struct cpufreq_frequency_table *exynos_of_parse_freq_table( { struct device_node *node = info->dev->of_node; struct cpufreq_frequency_table *ft, *ret = NULL; + int len, num, i = 0, k; struct property *pp; - int len, num, i = 0; u32 *of_f_tab; if (!node) @@ -357,29 +366,29 @@ struct cpufreq_frequency_table *exynos_of_parse_freq_table( } /* - * Here + 2 is required for CPUFREQ_ENTRY_INVALID and - * CPUFREQ_TABLE_END + * Here + 1 is required for CPUFREQ_TABLE_END * * Number of those entries must correspond to the apll_freq_4412 table */ - ft = kzalloc(sizeof(struct cpufreq_frequency_table) * (num + 2), - GFP_KERNEL); + ft = kzalloc(sizeof(struct cpufreq_frequency_table) * + (info->freq_levels + 1), GFP_KERNEL); if (!ft) { pr_err("%s: Allocation failed\n", __func__); goto err_of_f_tab; } - ft[0].index = L0; - ft[0].frequency = CPUFREQ_ENTRY_INVALID; + i = info->freq_levels; + ft[i].index = 0; + ft[i].frequency = CPUFREQ_TABLE_END; - for (i = 1; i <= num; i++) { + for (i--, k = num - 1; i >= 0; i--, k--) { ft[i].index = i; - ft[i].frequency = of_f_tab[i-1]; + if (k < 0) + ft[i].frequency = CPUFREQ_ENTRY_INVALID; + else + ft[i].frequency = of_f_tab[k]; } - ft[i].index = 0; - ft[i].frequency = CPUFREQ_TABLE_END; - ret = ft; err_of_f_tab: diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h index cb08d2850d6..5fe15fad16f 100644 --- a/drivers/cpufreq/exynos-cpufreq.h +++ b/drivers/cpufreq/exynos-cpufreq.h @@ -39,6 +39,7 @@ struct exynos_dvfs_info { unsigned int pll_safe_idx; struct clk *cpu_clk; unsigned int *volt_table; + unsigned int freq_levels; struct cpufreq_frequency_table *freq_table; void (*set_freq)(unsigned int, unsigned int); bool (*need_apll_change)(unsigned int, unsigned int); diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index e92d19be2c8..16ffbece2c5 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c @@ -27,8 +27,9 @@ static struct clk *sclk_mpll; static struct clk *mout_apll; static unsigned int exynos4x12_volt_table[] = { - 1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500, - 1000000, 987500, 975000, 950000, 925000, 900000, 900000 + 1400000, 1350000, 1350000, 1300000, 1225000, 1175000, + 1125000, 1075000, 1037500, 1012500, 1000000, 987500, + 975000, 925000, 925000, 925000, 900000 }; static struct cpufreq_frequency_table exynos4x12_freq_table[] = { @@ -83,6 +84,9 @@ static struct apll_freq apll_freq_4412[] = { * clock divider for COPY, HPM, CORES * PLL M, P, S */ + APLL_FREQ(1800, 0, 3, 7, 0, 6, 1, 2, 0, 7, 0, 7, 300, 4, 0), + APLL_FREQ(1704, 0, 3, 7, 0, 6, 1, 2, 0, 7, 0, 7, 213, 3, 0), + APLL_FREQ(1600, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 200, 3, 0), APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0), APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0), APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0), @@ -186,10 +190,13 @@ int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info) if (IS_ERR(mout_apll)) goto err_mout_apll; - if (soc_is_exynos4212()) + if (soc_is_exynos4212()) { + info->freq_levels = ARRAY_SIZE(apll_freq_4212); apll_freq_4x12 = apll_freq_4212; - else + } else { + info->freq_levels = ARRAY_SIZE(apll_freq_4412); apll_freq_4x12 = apll_freq_4412; + } info->mpll_freq_khz = rate; /* 800Mhz */ diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 24f8ae3f376..de1e0a1bffd 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -429,6 +429,10 @@ enum pl330_chan_op { PL330_OP_ABORT, /* Stop xfer and flush queue */ PL330_OP_FLUSH, + /* Pause xfer and halt channel */ + PL330_OP_PAUSE, + /* Resume xfer and restart channel */ + PL330_OP_RESUME, }; struct _xfer_spec { @@ -1235,6 +1239,49 @@ static bool _start(struct pl330_thread *thrd) } } +static bool _pause(struct pl330_thread *thrd) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + u8 insn[6] = {0, 0, 0, 0, 0, 0}; + + if (_state(thrd) == PL330_STATE_FAULT_COMPLETING) + UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING); + + /* Return false if dma channel has fault */ + if (_state(thrd) == PL330_STATE_COMPLETING || + _state(thrd) == PL330_STATE_KILLING || + _state(thrd) == PL330_STATE_FAULTING) + return false; + + _emit_WFE(0, insn, thrd->ev, 1); + + /* Stop generating interrupts for SEV */ + writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN); + + _execute_DBGINSN(thrd, insn, is_manager(thrd)); + + return true; +} + +static bool _resume(struct pl330_thread *thrd) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + + if (_state(thrd) == PL330_STATE_FAULT_COMPLETING) + UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING); + + /* Return false if dma channel has fault */ + if (_state(thrd) == PL330_STATE_COMPLETING || + _state(thrd) == PL330_STATE_KILLING || + _state(thrd) == PL330_STATE_FAULTING) + return false; + + /* Start generating interrupts for SEV */ + writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN); + + return true; +} + static inline int _ldst_memtomem(unsigned dry_run, u8 buf[], const struct _xfer_spec *pxs, int cyc) { @@ -1820,6 +1867,16 @@ static int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op) ret = -EIO; break; + case PL330_OP_PAUSE: + if ((active != -1) && !_pause(thrd)) + ret = -EIO; + break; + + case PL330_OP_RESUME: + if ((active != -1) && !_resume(thrd)) + ret = -EIO; + break; + default: ret = -EINVAL; } @@ -2416,6 +2473,16 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned pch->burst_len = slave_config->src_maxburst; } break; + case DMA_PAUSE: + spin_lock_irqsave(&pch->lock, flags); + pl330_chan_ctrl(pch->pl330_chid, PL330_OP_PAUSE); + spin_unlock_irqrestore(&pch->lock, flags); + break; + case DMA_RESUME: + spin_lock_irqsave(&pch->lock, flags); + pl330_chan_ctrl(pch->pl330_chid, PL330_OP_RESUME); + spin_unlock_irqrestore(&pch->lock, flags); + break; default: dev_err(pch->dmac->pif.dev, "Not supported command.\n"); return -ENXIO; @@ -2883,7 +2950,7 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan, caps->src_addr_widths = PL330_DMA_BUSWIDTHS; caps->dstn_addr_widths = PL330_DMA_BUSWIDTHS; caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - caps->cmd_pause = false; + caps->cmd_pause = true; caps->cmd_terminate = true; return 0; diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index f29148bcbbc..51758b83633 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -28,6 +28,7 @@ #include <linux/extcon.h> #include <linux/regmap.h> #include <linux/irqdomain.h> +#include <linux/delay.h> #define DEV_NAME "max77693-muic" #define DELAY_MS_DEFAULT 20000 /* unit: millisecond */ @@ -600,6 +601,75 @@ static int max77693_muic_dock_button_handler(struct max77693_muic_info *info, return 0; } +void max77693_otg_control(struct max77693_muic_info *info, int enable) +{ + static u8 chg_int_state; + u8 int_mask, cdetctrl1, chg_cnfg_00; + dev_dbg(info->dev, "%s: enable(%d)\n", __func__, enable); + + if (enable) { + /* disable charger interrupt */ + max77693_read_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, &int_mask); + chg_int_state = int_mask; + int_mask |= (1 << 4); /* disable chgin intr */ + int_mask |= (1 << 6); /* disable chg */ + int_mask &= ~(1 << 0); /* enable byp intr */ + max77693_write_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, int_mask); + + /* disable charger detection */ + max77693_read_reg(info->max77693->regmap_muic, + MAX77693_MUIC_REG_CDETCTRL1, &cdetctrl1); + cdetctrl1 &= ~(1 << 0); + max77693_write_reg(info->max77693->regmap_muic, + MAX77693_MUIC_REG_CDETCTRL1, cdetctrl1); + + /* OTG on, boost on, DIS_MUIC_CTRL=1 */ + max77693_read_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_00, &chg_cnfg_00); + chg_cnfg_00 &= ~(CHG_CNFG_00_CHG_MASK + | CHG_CNFG_00_OTG_MASK + | CHG_CNFG_00_BUCK_MASK + | CHG_CNFG_00_BOOST_MASK + | CHG_CNFG_00_DIS_MUIC_CTRL_MASK); + chg_cnfg_00 |= (CHG_CNFG_00_OTG_MASK + | CHG_CNFG_00_BOOST_MASK + | CHG_CNFG_00_DIS_MUIC_CTRL_MASK); + max77693_write_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_00, chg_cnfg_00); + } else { + /* OTG off, boost off, (buck on), + DIS_MUIC_CTRL = 0 unless CHG_ENA = 1 */ + max77693_read_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_00, &chg_cnfg_00); + chg_cnfg_00 &= ~(CHG_CNFG_00_OTG_MASK + | CHG_CNFG_00_BOOST_MASK + | CHG_CNFG_00_DIS_MUIC_CTRL_MASK); + chg_cnfg_00 |= CHG_CNFG_00_BUCK_MASK; + max77693_write_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_00, chg_cnfg_00); + + msleep(50); + + /* enable charger detection */ + max77693_read_reg(info->max77693->regmap_muic, + MAX77693_MUIC_REG_CDETCTRL1, &cdetctrl1); + cdetctrl1 |= (1 << 0); + max77693_write_reg(info->max77693->regmap_muic, + MAX77693_MUIC_REG_CDETCTRL1, cdetctrl1); + + /* enable charger interrupt */ + max77693_write_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, chg_int_state); + max77693_read_reg(info->max77693->regmap, + MAX77693_CHG_REG_CHG_INT_MASK, &int_mask); + } + + dev_dbg(info->dev, "%s: INT_MASK(0x%x), CDETCTRL1(0x%x), CHG_CNFG_00(0x%x)\n", + __func__, int_mask, cdetctrl1, chg_cnfg_00); +} + static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) { int cable_type_gnd; @@ -617,6 +687,7 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) if (ret < 0) return ret; extcon_set_cable_state(info->edev, "USB-Host", attached); + max77693_otg_control(info, attached); break; case MAX77693_MUIC_GND_AV_CABLE_LOAD: /* Audio Video Cable with load, PATH:AUDIO */ @@ -1250,9 +1321,6 @@ static int max77693_muic_probe(struct platform_device *pdev) delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } - /* Set initial path for UART */ - max77693_muic_set_path(info, info->path_uart, true); - /* Check revision number of MUIC device*/ ret = max77693_read_reg(info->max77693->regmap_muic, MAX77693_MUIC_REG_ID, &id); diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index ac10b5eedef..988309c5cc8 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -27,6 +27,7 @@ config DRM_EXYNOS_FIMD bool "Exynos DRM FIMD" depends on OF && DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM select FB_MODE_HELPERS + select MFD_SYSCON select VIDEOMODE_HELPERS help Choose this option if you want to use Exynos FIMD for DRM. diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index bc694364f19..22a8d1b8f64 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -85,8 +85,10 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) if (mode > DRM_MODE_DPMS_ON) { /* wait for the completion of page flip. */ - wait_event(exynos_crtc->pending_flip_queue, - atomic_read(&exynos_crtc->pending_flip) == 0); + if (!wait_event_timeout(exynos_crtc->pending_flip_queue, + !atomic_read(&exynos_crtc->pending_flip), + HZ/20)) + atomic_set(&exynos_crtc->pending_flip, 0); drm_vblank_off(crtc->dev, exynos_crtc->pipe); } @@ -353,6 +355,7 @@ out_fence: spin_lock_irq(&dev->event_lock); drm_vblank_put(dev, exynos_crtc->pipe); list_del(&event->base.link); + atomic_set(&exynos_crtc->pending_flip, 0); spin_unlock_irq(&dev->event_lock); mutex_unlock(&dev->struct_mutex); @@ -611,3 +614,14 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) manager->ops->wait_for_vblank(manager); } } + +int exynos_drm_crtc_te_handler(struct drm_crtc *crtc) +{ + struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; + int ret = 0; + + if (manager->ops->te_handler) + ret = manager->ops->te_handler(manager); + + return ret; +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index c27b66cc5d2..eb78c16e52c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -32,4 +32,11 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos); void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos); void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos); +/* + * This function calls the crtc device(manager)'s te_handler() callback + * to trigger to transfer video image at the tearing effect synchronization + * signal. + */ +int exynos_drm_crtc_te_handler(struct drm_crtc *crtc); + #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index d4c7dda847c..773f8c3fdf5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -15,6 +15,8 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <linux/anon_inodes.h> + #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" @@ -150,6 +152,10 @@ static int exynos_drm_unload(struct drm_device *dev) return 0; } +static const struct file_operations exynos_drm_gem_fops = { + .mmap = exynos_drm_gem_mmap_buffer, +}; + static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) { struct drm_connector *connector; @@ -188,6 +194,8 @@ static int exynos_drm_resume(struct drm_device *dev) static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv; + struct file *anon_filp; + int ret; file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); if (!file_priv) @@ -195,7 +203,29 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) file->driver_priv = file_priv; - return exynos_drm_subdrv_open(dev, file); + ret = exynos_drm_subdrv_open(dev, file); + if (ret) + goto err_file_priv_free; + + anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops, + NULL, 0); + if (IS_ERR(anon_filp)) { + ret = PTR_ERR(anon_filp); + goto err_subdrv_close; + } + + anon_filp->f_mode = FMODE_READ | FMODE_WRITE; + file_priv->anon_filp = anon_filp; + + return ret; + +err_subdrv_close: + exynos_drm_subdrv_close(dev, file); + +err_file_priv_free: + kfree(file_priv); + file->driver_priv = NULL; + return ret; } static void exynos_drm_preclose(struct drm_device *dev, @@ -207,6 +237,7 @@ static void exynos_drm_preclose(struct drm_device *dev, static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) { struct exynos_drm_private *private = dev->dev_private; + struct drm_exynos_file_private *file_priv; struct drm_pending_vblank_event *v, *vt; struct drm_pending_event *e, *et; unsigned long flags; @@ -232,6 +263,9 @@ static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) } spin_unlock_irqrestore(&dev->event_lock, flags); + file_priv = file->driver_priv; + if (file_priv->anon_filp) + fput(file_priv->anon_filp); kfree(file->driver_priv); file->driver_priv = NULL; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index a8002cc4981..3e825229bb0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -186,6 +186,8 @@ struct exynos_drm_display { * @win_commit: apply hardware specific overlay data to registers. * @win_enable: enable hardware specific overlay. * @win_disable: disable hardware specific overlay. + * @te_handler: trigger to transfer video image at the tearing effect + * synchronization signal if there is a page flip request. */ struct exynos_drm_manager; struct exynos_drm_manager_ops { @@ -207,6 +209,7 @@ struct exynos_drm_manager_ops { void (*win_commit)(struct exynos_drm_manager *mgr, int zpos); void (*win_enable)(struct exynos_drm_manager *mgr, int zpos); void (*win_disable)(struct exynos_drm_manager *mgr, int zpos); + int (*te_handler)(struct exynos_drm_manager *mgr); }; /* @@ -243,6 +246,7 @@ struct exynos_drm_ipp_private { struct drm_exynos_file_private { struct exynos_drm_g2d_private *g2d_priv; struct exynos_drm_ipp_private *ipp_priv; + struct file *anon_filp; }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 2d105ce1ee6..03efe88d29f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -17,12 +17,14 @@ #include <linux/clk.h> #include <linux/irq.h> +#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/regulator/consumer.h> #include <video/mipi_display.h> #include <video/videomode.h> +#include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" /* returns true iff both arguments logically differs */ @@ -53,9 +55,12 @@ /* FIFO memory AC characteristic register */ #define DSIM_PLLCTRL_REG 0x4c /* PLL control register */ -#define DSIM_PLLTMR_REG 0x50 /* PLL timer register */ #define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */ #define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */ +#define DSIM_PHYCTRL_REG 0x5c +#define DSIM_PHYTIMING_REG 0x64 +#define DSIM_PHYTIMING1_REG 0x68 +#define DSIM_PHYTIMING2_REG 0x6c /* DSIM_STATUS */ #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) @@ -199,6 +204,24 @@ #define DSIM_PLL_M(x) ((x) << 4) #define DSIM_PLL_S(x) ((x) << 1) +/* DSIM_PHYCTRL */ +#define DSIM_PHYCTRL_ULPS_EXIT(x) (((x) & 0x1ff) << 0) + +/* DSIM_PHYTIMING */ +#define DSIM_PHYTIMING_LPX(x) ((x) << 8) +#define DSIM_PHYTIMING_HS_EXIT(x) ((x) << 0) + +/* DSIM_PHYTIMING1 */ +#define DSIM_PHYTIMING1_CLK_PREPARE(x) ((x) << 24) +#define DSIM_PHYTIMING1_CLK_ZERO(x) ((x) << 16) +#define DSIM_PHYTIMING1_CLK_POST(x) ((x) << 8) +#define DSIM_PHYTIMING1_CLK_TRAIL(x) ((x) << 0) + +/* DSIM_PHYTIMING2 */ +#define DSIM_PHYTIMING2_HS_PREPARE(x) ((x) << 16) +#define DSIM_PHYTIMING2_HS_ZERO(x) ((x) << 8) +#define DSIM_PHYTIMING2_HS_TRAIL(x) ((x) << 0) + #define DSI_MAX_BUS_WIDTH 4 #define DSI_NUM_VIRTUAL_CHANNELS 4 #define DSI_TX_FIFO_SIZE 2048 @@ -232,6 +255,12 @@ struct exynos_dsi_transfer { #define DSIM_STATE_INITIALIZED BIT(1) #define DSIM_STATE_CMD_LPM BIT(2) +struct exynos_dsi_driver_data { + unsigned int plltmr_reg; + + unsigned int has_freqband:1; +}; + struct exynos_dsi { struct mipi_dsi_host dsi_host; struct drm_connector connector; @@ -261,11 +290,39 @@ struct exynos_dsi { spinlock_t transfer_lock; /* protects transfer_list */ struct list_head transfer_list; + + struct exynos_dsi_driver_data *driver_data; }; #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) +static struct exynos_dsi_driver_data exynos4_dsi_driver_data = { + .plltmr_reg = 0x50, + .has_freqband = 1, +}; + +static struct exynos_dsi_driver_data exynos5_dsi_driver_data = { + .plltmr_reg = 0x58, +}; + +static struct of_device_id exynos_dsi_of_match[] = { + { .compatible = "samsung,exynos4210-mipi-dsi", + .data = &exynos4_dsi_driver_data }, + { .compatible = "samsung,exynos5420-mipi-dsi", + .data = &exynos5_dsi_driver_data }, + { } +}; + +static inline struct exynos_dsi_driver_data *exynos_dsi_get_driver_data( + struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(exynos_dsi_of_match, &pdev->dev); + + return (struct exynos_dsi_driver_data *)of_id->data; +} + static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) { if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) @@ -339,14 +396,9 @@ static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, unsigned long freq) { - static const unsigned long freq_bands[] = { - 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, - 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, - 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, - 770 * MHZ, 870 * MHZ, 950 * MHZ, - }; + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; unsigned long fin, fout; - int timeout, band; + int timeout; u8 p, s; u16 m; u32 reg; @@ -367,18 +419,30 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, "failed to find PLL PMS for requested frequency\n"); return -EFAULT; } + dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d)\n", fout, p, m, s); - for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) - if (fout < freq_bands[band]) - break; + writel(500, dsi->reg_base + driver_data->plltmr_reg); + + reg = DSIM_PLL_EN | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); + + if (driver_data->has_freqband) { + static const unsigned long freq_bands[] = { + 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, + 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, + 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, + 770 * MHZ, 870 * MHZ, 950 * MHZ, + }; + int band; - dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d), band %d\n", fout, - p, m, s, band); + for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) + if (fout < freq_bands[band]) + break; - writel(500, dsi->reg_base + DSIM_PLLTMR_REG); + dev_dbg(dsi->dev, "band %d\n", band); + + reg |= DSIM_FREQ_BAND(band); + } - reg = DSIM_FREQ_BAND(band) | DSIM_PLL_EN - | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); timeout = 1000; @@ -432,6 +496,59 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) return 0; } +static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) +{ + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; + u32 reg; + + if (driver_data->has_freqband) + return; + + /* B D-PHY: D-PHY Master & Slave Analog Block control */ + reg = DSIM_PHYCTRL_ULPS_EXIT(0x0af); + writel(reg, dsi->reg_base + DSIM_PHYCTRL_REG); + + /* + * T LPX: Transmitted length of any Low-Power state period + * T HS-EXIT: Time that the transmitter drives LP-11 following a HS + * burst + */ + reg = DSIM_PHYTIMING_LPX(0x06) | DSIM_PHYTIMING_HS_EXIT(0x0b); + writel(reg, dsi->reg_base + DSIM_PHYTIMING_REG); + + /* + * T CLK-PREPARE: Time that the transmitter drives the Clock Lane LP-00 + * Line state immediately before the HS-0 Line state starting the + * HS transmission + * T CLK-ZERO: Time that the transmitter drives the HS-0 state prior to + * transmitting the Clock. + * T CLK_POST: Time that the transmitter continues to send HS clock + * after the last associated Data Lane has transitioned to LP Mode + * Interval is defined as the period from the end of T HS-TRAIL to + * the beginning of T CLK-TRAIL + * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after + * the last payload clock bit of a HS transmission burst + */ + reg = DSIM_PHYTIMING1_CLK_PREPARE(0x07) | + DSIM_PHYTIMING1_CLK_ZERO(0x27) | + DSIM_PHYTIMING1_CLK_POST(0x0d) | + DSIM_PHYTIMING1_CLK_TRAIL(0x08); + writel(reg, dsi->reg_base + DSIM_PHYTIMING1_REG); + + /* + * T HS-PREPARE: Time that the transmitter drives the Data Lane LP-00 + * Line state immediately before the HS-0 Line state starting the + * HS transmission + * T HS-ZERO: Time that the transmitter drives the HS-0 state prior to + * transmitting the Sync sequence. + * T HS-TRAIL: Time that the transmitter drives the flipped differential + * state after last payload data bit of a HS transmission burst + */ + reg = DSIM_PHYTIMING2_HS_PREPARE(0x09) | DSIM_PHYTIMING2_HS_ZERO(0x0d) | + DSIM_PHYTIMING2_HS_TRAIL(0x0b); + writel(reg, dsi->reg_base + DSIM_PHYTIMING2_REG); +} + static void exynos_dsi_disable_clock(struct exynos_dsi *dsi) { u32 reg; @@ -472,8 +589,6 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) reg |= DSIM_MFLUSH_VS; - if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) - reg |= DSIM_EOT_DISABLE; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) reg |= DSIM_SYNC_INFORM; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) @@ -490,6 +605,9 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) reg |= DSIM_HSA_MODE; } + if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + reg |= DSIM_EOT_DISABLE; + switch (dsi->format) { case MIPI_DSI_FMT_RGB888: reg |= DSIM_MAIN_PIX_FORMAT_RGB888; @@ -945,10 +1063,11 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) static int exynos_dsi_init(struct exynos_dsi *dsi) { - exynos_dsi_enable_clock(dsi); exynos_dsi_reset(dsi); enable_irq(dsi->irq); + exynos_dsi_enable_clock(dsi); exynos_dsi_wait_for_reset(dsi); + exynos_dsi_set_phy_ctrl(dsi); exynos_dsi_init_link(dsi); return 0; @@ -1031,10 +1150,22 @@ static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, return (ret < 0) ? ret : xfer.rx_done; } +static int exynos_dsi_host_te_handler(struct mipi_dsi_host *host) +{ + struct exynos_dsi *dsi = host_to_dsi(host); + struct drm_encoder *encoder = dsi->encoder; + + if (!(dsi->state & DSIM_STATE_ENABLED)) + return -EPERM; + + return exynos_drm_crtc_te_handler(encoder->crtc); +} + static const struct mipi_dsi_host_ops exynos_dsi_ops = { .attach = exynos_dsi_host_attach, .detach = exynos_dsi_host_detach, .transfer = exynos_dsi_host_transfer, + .te_handler = exynos_dsi_host_te_handler, }; static int exynos_dsi_poweron(struct exynos_dsi *dsi) @@ -1398,6 +1529,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) dsi->dsi_host.dev = &pdev->dev; dsi->dev = &pdev->dev; + dsi->driver_data = exynos_dsi_get_driver_data(pdev); ret = exynos_dsi_parse_dt(dsi); if (ret) @@ -1502,11 +1634,6 @@ static const struct dev_pm_ops exynos_dsi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume) }; -static struct of_device_id exynos_dsi_of_match[] = { - { .compatible = "samsung,exynos4210-mipi-dsi" }, - { } -}; - struct platform_driver dsi_driver = { .probe = exynos_dsi_probe, .remove = exynos_dsi_remove, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index c632757d850..2d0d94132c9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -61,6 +61,24 @@ /* color key value register for hardware window 1 ~ 4. */ #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) +/* I80 / RGB trigger control register */ +#define TRIGCON 0x1A4 +#define TRGMODE_I80_RGB_ENABLE_I80 (1 << 0) +#define SWTRGCMD_I80_RGB_ENABLE (1 << 1) + +/* display mode change control register except exynos4 */ +#define VIDOUT_CON 0x000 +#define VIDOUT_CON_F_I80_LDI0 (0x2 << 8) + +/* I80 interface control for main LDI register */ +#define I80IFCONFAx(x) (0x1B0 + (x) * 4) +#define I80IFCONFBx(x) (0x1B8 + (x) * 4) +#define LCD_CS_SETUP(x) ((x) << 16) +#define LCD_WR_SETUP(x) ((x) << 12) +#define LCD_WR_ACTIVE(x) ((x) << 8) +#define LCD_WR_HOLD(x) ((x) << 4) +#define I80IFEN_ENABLE (1 << 0) + /* FIMD has totally five hardware windows. */ #define WINDOWS_NR 5 @@ -68,12 +86,14 @@ struct fimd_driver_data { unsigned int timing_base; - unsigned int lcdblk_reg; - unsigned int lcdblk_fimdbypass; + unsigned int lcdblk_off; + unsigned int lcdblk_vt_shift; + unsigned int lcdblk_bypass_shift; unsigned int has_shadowcon:1; unsigned int has_clksel:1; unsigned int has_limited_fmt:1; + unsigned int has_vidoutcon:1; }; static struct fimd_driver_data s3c64xx_fimd_driver_data = { @@ -84,16 +104,19 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = { static struct fimd_driver_data exynos4_fimd_driver_data = { .timing_base = 0x0, - .lcdblk_reg = 0x210, - .lcdblk_fimdbypass = 1, + .lcdblk_off = 0x210, + .lcdblk_vt_shift = 10, + .lcdblk_bypass_shift = 1, .has_shadowcon = 1, }; static struct fimd_driver_data exynos5_fimd_driver_data = { .timing_base = 0x20000, - .lcdblk_reg = 0x210, - .lcdblk_fimdbypass = 15, + .lcdblk_off = 0x214, + .lcdblk_vt_shift = 24, + .lcdblk_bypass_shift = 15, .has_shadowcon = 1, + .has_vidoutcon = 1, }; struct fimd_win_data { @@ -118,16 +141,23 @@ struct fimd_context { struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; - struct drm_display_mode mode; struct regmap *sysreg; + struct drm_display_mode mode; struct fimd_win_data win_data[WINDOWS_NR]; unsigned int default_win; unsigned long irq_flags; + u32 vidcon0; u32 vidcon1; + u32 vidout_con; + u32 i80ifcon; + bool i80_if; bool suspended; int pipe; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; + atomic_t win_updated; + atomic_t triggering; + spinlock_t win_updated_lock; struct exynos_drm_panel_info panel; struct fimd_driver_data *driver_data; @@ -248,6 +278,14 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; u32 clkdiv; + if (ctx->i80_if) { + /* + * The frame done interrupt should be occurred prior to the + * next TE signal. + */ + ideal_clk *= 2; + } + /* Find the clock divider value that gets us closest to ideal_clk */ clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); @@ -276,12 +314,10 @@ static void fimd_commit(struct exynos_drm_manager *mgr) { struct fimd_context *ctx = mgr->ctx; struct drm_display_mode *mode = &ctx->mode; - struct fimd_driver_data *driver_data; + struct fimd_driver_data *driver_data = ctx->driver_data; + void *timing_base = ctx->regs + driver_data->timing_base; u32 val, clkdiv; - int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; - int ret; - driver_data = ctx->driver_data; if (ctx->suspended) return; @@ -289,37 +325,65 @@ static void fimd_commit(struct exynos_drm_manager *mgr) if (mode->htotal == 0 || mode->vtotal == 0) return; - /* enable FIMDBYPASS bit of LCDBLK0 */ - ret = regmap_update_bits(ctx->sysreg, driver_data->lcdblk_reg, - 0x1 << driver_data->lcdblk_fimdbypass, - 0x1 << driver_data->lcdblk_fimdbypass); - if (ret < 0) { - DRM_ERROR("failed to update sysreg.\n"); - return; - } + if (ctx->i80_if) { + val = ctx->i80ifcon | I80IFEN_ENABLE; + writel(val, timing_base + I80IFCONFAx(0)); - /* setup polarity values from machine code. */ - writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); + /* disable auto frame rate */ + writel(0, timing_base + I80IFCONFBx(0)); - /* setup vertical timing values. */ - vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; - vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; - vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; + if (ctx->vidout_con) + writel(ctx->vidout_con, timing_base + VIDOUT_CON); - val = VIDTCON0_VBPD(vbpd - 1) | - VIDTCON0_VFPD(vfpd - 1) | - VIDTCON0_VSPW(vsync_len - 1); - writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); - - /* setup horizontal timing values. */ - hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; - hbpd = mode->crtc_htotal - mode->crtc_hsync_end; - hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; + /* set video type selection to I80 interface */ + if (ctx->sysreg && regmap_update_bits(ctx->sysreg, + driver_data->lcdblk_off, + 0x3 << driver_data->lcdblk_vt_shift, + 0x1 << driver_data->lcdblk_vt_shift)) { + DRM_ERROR("Failed to update sysreg for I80 i/f.\n"); + return; + } + } else { + int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; + u32 vidcon1; + + /* setup polarity values */ + vidcon1 = ctx->vidcon1; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + vidcon1 |= VIDCON1_INV_VSYNC; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + vidcon1 |= VIDCON1_INV_HSYNC; + writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); + + /* setup vertical timing values. */ + vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; + vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; + vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; + + val = VIDTCON0_VBPD(vbpd - 1) | + VIDTCON0_VFPD(vfpd - 1) | + VIDTCON0_VSPW(vsync_len - 1); + writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); + + /* setup horizontal timing values. */ + hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + hbpd = mode->crtc_htotal - mode->crtc_hsync_end; + hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; + + val = VIDTCON1_HBPD(hbpd - 1) | + VIDTCON1_HFPD(hfpd - 1) | + VIDTCON1_HSPW(hsync_len - 1); + writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); + } - val = VIDTCON1_HBPD(hbpd - 1) | - VIDTCON1_HFPD(hfpd - 1) | - VIDTCON1_HSPW(hsync_len - 1); - writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); + /* set bypass selection */ + if (ctx->sysreg && regmap_update_bits(ctx->sysreg, + driver_data->lcdblk_off, + 0x1 << driver_data->lcdblk_bypass_shift, + 0x1 << driver_data->lcdblk_bypass_shift)) { + DRM_ERROR("Failed to update sysreg for bypass setting.\n"); + return; + } /* setup horizontal and vertical display size. */ val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | @@ -332,7 +396,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr) * fields of register with prefix '_F' would be updated * at vsync(same as dma start) */ - val = VIDCON0_ENVID | VIDCON0_ENVID_F; + val = ctx->vidcon0; + val |= VIDCON0_ENVID | VIDCON0_ENVID_F; if (ctx->driver_data->has_clksel) val |= VIDCON0_CLKSEL_LCD; @@ -657,6 +722,14 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) } win_data->enabled = true; + + if (ctx->i80_if) { + unsigned long flags; + + spin_lock_irqsave(&ctx->win_updated_lock, flags); + atomic_set(&ctx->win_updated, 1); + spin_unlock_irqrestore(&ctx->win_updated_lock, flags); + } } static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) @@ -846,6 +919,68 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) } } +static void fimd_trigger(struct device *dev) +{ + struct exynos_drm_manager *mgr = get_fimd_manager(dev); + struct fimd_context *ctx = mgr->ctx; + struct fimd_driver_data *driver_data = ctx->driver_data; + void *timing_base = ctx->regs + driver_data->timing_base; + u32 reg; + + atomic_set(&ctx->triggering, 1); + + reg = readl(ctx->regs + VIDINTCON0); + reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE | + VIDINTCON0_INT_SYSMAINCON); + writel(reg, ctx->regs + VIDINTCON0); + + reg = readl(timing_base + TRIGCON); + reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE); + writel(reg, timing_base + TRIGCON); +} + +static int fimd_te_handler(struct exynos_drm_manager *mgr) +{ + struct fimd_context *ctx = mgr->ctx; + unsigned long flags; + + /* Checks the crtc is detached already from encoder */ + if (ctx->pipe < 0 || !ctx->drm_dev) + return -EINVAL; + + /* + * Skips to trigger if in triggering state, because multiple triggering + * requests can cause panel reset. + */ + if (atomic_read(&ctx->triggering)) + return 0; + + spin_lock_irqsave(&ctx->win_updated_lock, flags); + + /* + * If there is a page flip request, triggers and handles the page flip + * event so that current fb can be updated into panel GRAM. + */ + if (atomic_read(&ctx->win_updated)) { + atomic_set(&ctx->win_updated, 0); + + fimd_trigger(ctx->dev); + } + + spin_unlock_irqrestore(&ctx->win_updated_lock, flags); + + /* Wakes up vsync event queue */ + if (atomic_read(&ctx->wait_vsync_event)) { + atomic_set(&ctx->wait_vsync_event, 0); + wake_up(&ctx->wait_vsync_queue); + + if (!atomic_read(&ctx->triggering)) + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + } + + return 0; +} + static struct exynos_drm_manager_ops fimd_manager_ops = { .initialize = fimd_mgr_initialize, .remove = fimd_mgr_remove, @@ -859,6 +994,7 @@ static struct exynos_drm_manager_ops fimd_manager_ops = { .win_mode_set = fimd_win_mode_set, .win_commit = fimd_win_commit, .win_disable = fimd_win_disable, + .te_handler = fimd_te_handler, }; static struct exynos_drm_manager fimd_manager = { @@ -869,26 +1005,40 @@ static struct exynos_drm_manager fimd_manager = { static irqreturn_t fimd_irq_handler(int irq, void *dev_id) { struct fimd_context *ctx = (struct fimd_context *)dev_id; - u32 val; + u32 val, clear_bit; val = readl(ctx->regs + VIDINTCON1); - if (val & VIDINTCON1_INT_FRAME) - /* VSYNC interrupt */ - writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); + clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME; + if (val & clear_bit) + writel(clear_bit, ctx->regs + VIDINTCON1); /* check the crtc is detached already from encoder */ if (ctx->pipe < 0 || !ctx->drm_dev) goto out; - drm_handle_vblank(ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + if (ctx->i80_if) { + /* unset I80 frame done interrupt */ + val = readl(ctx->regs + VIDINTCON0); + val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON); + writel(val, ctx->regs + VIDINTCON0); - /* set wait vsync event to zero and wake up queue. */ - if (atomic_read(&ctx->wait_vsync_event)) { - atomic_set(&ctx->wait_vsync_event, 0); - wake_up(&ctx->wait_vsync_queue); + /* exit triggering mode */ + atomic_set(&ctx->triggering, 0); + + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + } else { + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + + /* set wait vsync event to zero and wake up queue. */ + if (atomic_read(&ctx->wait_vsync_event)) { + atomic_set(&ctx->wait_vsync_event, 0); + wake_up(&ctx->wait_vsync_queue); + } } + out: return IRQ_HANDLED; } @@ -897,6 +1047,7 @@ static int fimd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimd_context *ctx; + struct device_node *i80_if_timings; struct resource *res; int win; int ret = -EINVAL; @@ -910,12 +1061,49 @@ static int fimd_probe(struct platform_device *pdev) ctx->dev = dev; ctx->suspended = true; + ctx->driver_data = drm_fimd_get_driver_data(pdev); if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) ctx->vidcon1 |= VIDCON1_INV_VDEN; if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) ctx->vidcon1 |= VIDCON1_INV_VCLK; + i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings"); + if (i80_if_timings) { + u32 val; + + ctx->i80_if = true; + + if (ctx->driver_data->has_vidoutcon) + ctx->vidout_con |= VIDOUT_CON_F_I80_LDI0; + else + ctx->vidcon0 |= VIDCON0_VIDOUT_I80_LDI0; + ctx->vidcon0 |= VIDCON0_DSI_EN; + + if (of_property_read_u32(i80_if_timings, "cs-setup", &val)) + val = 0; + ctx->i80ifcon = LCD_CS_SETUP(val); + if (of_property_read_u32(i80_if_timings, "wr-setup", &val)) + val = 0; + ctx->i80ifcon |= LCD_WR_SETUP(val); + if (of_property_read_u32(i80_if_timings, "wr-active", &val)) + val = 1; + ctx->i80ifcon |= LCD_WR_ACTIVE(val); + if (of_property_read_u32(i80_if_timings, "wr-hold", &val)) + val = 0; + ctx->i80ifcon |= LCD_WR_HOLD(val); + + spin_lock_init(&ctx->win_updated_lock); + } + of_node_put(i80_if_timings); + + ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,sysreg"); + if (IS_ERR(ctx->sysreg)) { + dev_warn(dev, "failed to get system register.\n"); + ctx->sysreg = NULL; + } + ctx->bus_clk = devm_clk_get(dev, "fimd"); if (IS_ERR(ctx->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); @@ -934,7 +1122,8 @@ static int fimd_probe(struct platform_device *pdev) if (IS_ERR(ctx->regs)) return PTR_ERR(ctx->regs); - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + ctx->i80_if ? "lcd_sys" : "vsync"); if (!res) { dev_err(dev, "irq request failed.\n"); return -ENXIO; @@ -952,7 +1141,6 @@ static int fimd_probe(struct platform_device *pdev) if (IS_ERR(ctx->sysreg)) return PTR_ERR(ctx->sysreg); - ctx->driver_data = drm_fimd_get_driver_data(pdev); init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 55289cda85a..d88931d964d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -353,46 +353,22 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, &args->offset); } -static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev, - struct file *filp) -{ - struct drm_file *file_priv; - - /* find current process's drm_file from filelist. */ - list_for_each_entry(file_priv, &drm_dev->filelist, lhead) - if (file_priv->filp == filp) - return file_priv; - - WARN_ON(1); - - return ERR_PTR(-EFAULT); -} - -static int exynos_drm_gem_mmap_buffer(struct file *filp, +int exynos_drm_gem_mmap_buffer(struct file *filp, struct vm_area_struct *vma) { struct drm_gem_object *obj = filp->private_data; struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); struct drm_device *drm_dev = obj->dev; struct exynos_drm_gem_buf *buffer; - struct drm_file *file_priv; unsigned long vm_size; int ret; + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; vma->vm_private_data = obj; vma->vm_ops = drm_dev->driver->gem_vm_ops; - /* restore it to driver's fops. */ - filp->f_op = fops_get(drm_dev->driver->fops); - - file_priv = exynos_drm_find_drm_file(drm_dev, filp); - if (IS_ERR(file_priv)) - return PTR_ERR(file_priv); - - /* restore it to drm_file. */ - filp->private_data = file_priv; - update_vm_cache_attr(exynos_gem_obj, vma); vm_size = vma->vm_end - vma->vm_start; @@ -426,15 +402,13 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, return 0; } -static const struct file_operations exynos_drm_gem_fops = { - .mmap = exynos_drm_gem_mmap_buffer, -}; - int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_exynos_file_private *exynos_file_priv; struct drm_exynos_gem_mmap *args = data; struct drm_gem_object *obj; + struct file *anon_filp; unsigned int addr; if (!(dev->driver->driver_features & DRIVER_GEM)) { @@ -442,47 +416,25 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, return -ENODEV; } + mutex_lock(&dev->struct_mutex); + obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (!obj) { DRM_ERROR("failed to lookup gem object.\n"); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } - /* - * We have to use gem object and its fops for specific mmaper, - * but vm_mmap() can deliver only filp. So we have to change - * filp->f_op and filp->private_data temporarily, then restore - * again. So it is important to keep lock until restoration the - * settings to prevent others from misuse of filp->f_op or - * filp->private_data. - */ - mutex_lock(&dev->struct_mutex); - - /* - * Set specific mmper's fops. And it will be restored by - * exynos_drm_gem_mmap_buffer to dev->driver->fops. - * This is used to call specific mapper temporarily. - */ - file_priv->filp->f_op = &exynos_drm_gem_fops; - - /* - * Set gem object to private_data so that specific mmaper - * can get the gem object. And it will be restored by - * exynos_drm_gem_mmap_buffer to drm_file. - */ - file_priv->filp->private_data = obj; + exynos_file_priv = file_priv->driver_priv; + anon_filp = exynos_file_priv->anon_filp; + anon_filp->private_data = obj; - addr = vm_mmap(file_priv->filp, 0, args->size, - PROT_READ | PROT_WRITE, MAP_SHARED, 0); + addr = vm_mmap(anon_filp, 0, args->size, PROT_READ | PROT_WRITE, + MAP_SHARED, 0); drm_gem_object_unreference(obj); if (IS_ERR((void *)addr)) { - /* check filp->f_op, filp->private_data are restored */ - if (file_priv->filp->f_op == &exynos_drm_gem_fops) { - file_priv->filp->f_op = fops_get(dev->driver->fops); - file_priv->filp->private_data = file_priv; - } mutex_unlock(&dev->struct_mutex); return PTR_ERR((void *)addr); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 78a083302c6..d653c9cf22a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -126,6 +126,9 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data, int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int exynos_drm_gem_mmap_buffer(struct file *filp, + struct vm_area_struct *vma); + /* map user space allocated by malloc to pages. */ int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 337e4d69a38..eabf38bc858 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1903,6 +1903,11 @@ out: static void hdmi_dpms(struct exynos_drm_display *display, int mode) { + struct hdmi_context *hdata = display->ctx; + struct drm_encoder *encoder = hdata->encoder; + struct drm_crtc *crtc = encoder->crtc; + struct drm_crtc_helper_funcs *funcs = NULL; + DRM_DEBUG_KMS("mode %d\n", mode); switch (mode) { @@ -1912,6 +1917,20 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: + /* + * The SFRs of VP and Mixer are updated by Vertical Sync of + * Timing generator which is a part of HDMI so the sequence + * to disable TV Subsystem should be as following, + * VP -> Mixer -> HDMI + * + * Below codes will try to disable Mixer and VP(if used) + * prior to disabling HDMI. + */ + if (crtc) + funcs = crtc->helper_private; + if (funcs && funcs->dpms) + (*funcs->dpms)(crtc, mode); + hdmi_poweroff(display); break; default: diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index cca841a1638..5c1ebbab007 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -603,7 +603,7 @@ static void vp_win_reset(struct mixer_context *ctx) /* waiting until VP_SRESET_PROCESSING is 0 */ if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) break; - usleep_range(10000, 12000); + mdelay(10); } WARN(tries == 0, "failed to reset Video Processor\n"); } diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 4ec874da566..a54d89b5f55 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -29,5 +29,7 @@ config DRM_PANEL_S6E8AA0 depends on OF select DRM_MIPI_DSI select VIDEOMODE_HELPERS + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE endmenu diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 5782ff48f70..32b1434084c 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -19,6 +19,7 @@ #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> +#include <linux/backlight.h> #include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> @@ -92,9 +93,12 @@ struct s6e8aa0_variant { const s6e8aa0_gamma_table *gamma_tables; }; +#define S6E8AA0_STATE_BIT_ENABLED 0 + struct s6e8aa0 { struct device *dev; struct drm_panel panel; + struct backlight_device *backlight; struct regulator_bulk_data supplies[2]; int reset_gpio; @@ -107,6 +111,7 @@ struct s6e8aa0 { u32 width_mm; u32 height_mm; + unsigned long state; u8 version; u8 id; const struct s6e8aa0_variant *variant; @@ -891,6 +896,7 @@ static int s6e8aa0_disable(struct drm_panel *panel) { struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); + clear_bit(S6E8AA0_STATE_BIT_ENABLED, &ctx->state); s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF); msleep(40); @@ -914,6 +920,8 @@ static int s6e8aa0_enable(struct drm_panel *panel) if (ret < 0) s6e8aa0_disable(panel); + else + set_bit(S6E8AA0_STATE_BIT_ENABLED, &ctx->state); return ret; } @@ -948,6 +956,49 @@ static const struct drm_panel_funcs s6e8aa0_drm_funcs = { .get_modes = s6e8aa0_get_modes, }; +static int s6e8aa0_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static int s6e8aa0_set_brightness(struct backlight_device *bd) +{ + struct s6e8aa0 *ctx = bl_get_data(bd); + + bd->props.power = FB_BLANK_UNBLANK; + if (ctx->brightness != bd->props.brightness) { + ctx->brightness = bd->props.brightness; + if (test_bit(S6E8AA0_STATE_BIT_ENABLED, &ctx->state)) + s6e8aa0_brightness_set(ctx); + } + + return s6e8aa0_clear_error(ctx); +} + +static const struct backlight_ops s6e8aa0_backlight_ops = { + .get_brightness = s6e8aa0_get_brightness, + .update_status = s6e8aa0_set_brightness, +}; + +static void s6e8aa0_backlight_register(struct s6e8aa0 *ctx) +{ + struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = ctx->brightness, + .max_brightness = GAMMA_LEVEL_NUM - 1 + }; + struct device *dev = ctx->dev; + struct backlight_device *bd; + + bd = backlight_device_register("s6e8aa0-bl", dev, ctx, + &s6e8aa0_backlight_ops, &props); + if (IS_ERR(bd)) + dev_err(dev, "error registering backlight device (%ld)\n", + PTR_ERR(bd)); + else + ctx->backlight = bd; +} + static int s6e8aa0_parse_dt(struct s6e8aa0 *ctx) { struct device *dev = ctx->dev; @@ -1037,6 +1088,8 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) if (ret < 0) drm_panel_remove(&ctx->panel); + s6e8aa0_backlight_register(ctx); + return ret; } @@ -1044,6 +1097,8 @@ static int s6e8aa0_remove(struct mipi_dsi_device *dsi) { struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi); + if (ctx->backlight) + backlight_device_unregister(ctx->backlight); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index df064e8cd9d..8f2bde1fbd3 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1000,6 +1000,17 @@ config SENSORS_PCF8591 source drivers/hwmon/pmbus/Kconfig +config SENSORS_PWM_FAN + tristate "PWM fan" + depends on PWM + help + If you say yes here you get support for fans connected to PWM lines. + The driver uses the generic PWM interface, thus it will work on a + variety of SoCs. + + This driver can also be built as a module. If so, the module + will be called pwm-fan. + config SENSORS_SHT15 tristate "Sensiron humidity and temperature sensors. SHT15 and compat." depends on GPIOLIB diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d17d3e64f9f..fa7127e77da 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o +obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c new file mode 100644 index 00000000000..d5421c023b4 --- /dev/null +++ b/drivers/hwmon/pwm-fan.c @@ -0,0 +1,201 @@ +/* + * pwm-fan.c - Hwmon driver for fans connected to PWM lines. + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Author: Kamil Debski <k.debski@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/sysfs.h> + +#define MAX_PWM 255 + +struct pwm_fan_ctx { + struct mutex lock; + struct pwm_device *pwm; + unsigned char pwm_value; +}; + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + unsigned long pwm, duty; + ssize_t ret; + + if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM) + return -EINVAL; + + mutex_lock(&ctx->lock); + + if (ctx->pwm_value == pwm) + goto exit_set_pwm_no_change; + + if (pwm == 0) { + pwm_disable(ctx->pwm); + goto exit_set_pwm; + } + + duty = DIV_ROUND_UP(pwm * (ctx->pwm->period - 1), MAX_PWM); + ret = pwm_config(ctx->pwm, duty, ctx->pwm->period); + if (ret) + goto exit_set_pwm_err; + + if (ctx->pwm_value == 0) { + ret = pwm_enable(ctx->pwm); + if (ret) + goto exit_set_pwm_err; + } + +exit_set_pwm: + ctx->pwm_value = pwm; +exit_set_pwm_no_change: + ret = count; +exit_set_pwm_err: + mutex_unlock(&ctx->lock); + return ret; +} + +static ssize_t show_pwm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ctx->pwm_value); +} + + +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); + +static struct attribute *pwm_fan_attributes[] = { + &sensor_dev_attr_pwm1.dev_attr.attr, + NULL, +}; + +static const struct attribute_group pwm_fan_group = { + .attrs = pwm_fan_attributes, +}; + +static int pwm_fan_probe(struct platform_device *pdev) +{ + struct device *hwmon; + struct pwm_fan_ctx *ctx; + int duty_cycle; + int ret; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mutex_init(&ctx->lock); + + ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, 0); + if (IS_ERR(ctx->pwm)) { + dev_err(&pdev->dev, "Could not get PWM\n"); + return PTR_ERR(ctx->pwm); + } + + dev_set_drvdata(&pdev->dev, ctx); + platform_set_drvdata(pdev, ctx); + + /* Set duty cycle to maximum allowed */ + duty_cycle = ctx->pwm->period - 1; + ctx->pwm_value = MAX_PWM; + + ret = pwm_config(ctx->pwm, duty_cycle, ctx->pwm->period); + if (ret) { + dev_err(&pdev->dev, "Failed to configure PWM\n"); + return ret; + } + + /* Enable PWM output */ + ret = pwm_enable(ctx->pwm); + if (ret) { + dev_err(&pdev->dev, "Failed to enable PWM\n"); + return ret; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &pwm_fan_group); + if (ret) + return ret; + + hwmon = hwmon_device_register(&pdev->dev); + + if (IS_ERR(hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device"); + pwm_disable(ctx->pwm); + return PTR_ERR(hwmon); + } + return 0; +} + +static int pwm_fan_remove(struct platform_device *pdev) +{ + struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); + + if (ctx->pwm_value) + pwm_disable(ctx->pwm); + mutex_destroy(&ctx->lock); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pwm_fan_suspend(struct device *dev) +{ + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + if (ctx->pwm_value) + pwm_disable(ctx->pwm); + return 0; +} + +static int pwm_fan_resume(struct device *dev) +{ + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + if (ctx->pwm_value) + return pwm_enable(ctx->pwm); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); + +static struct of_device_id of_pwm_fan_match[] = { + { .compatible = "pwm-fan", }, + {}, +}; + +static struct platform_driver pwm_fan_driver = { + .probe = pwm_fan_probe, + .remove = pwm_fan_remove, + .driver = { + .name = "pwm-fan", + .pm = &pwm_fan_pm, + .of_match_table = of_pwm_fan_match, + }, +}; + +module_platform_driver(pwm_fan_driver); + +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); +MODULE_ALIAS("platform:pwm-fan"); +MODULE_DESCRIPTION("PWM FAN driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index 6ccc3f8c122..882739ba895 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -365,6 +365,9 @@ #define S5P_FIMV_H2R_CMD_SLEEP 5 #define S5P_FIMV_H2R_CMD_WAKEUP 6 +/* Host to RISC command options */ +#define S5P_FIMV_H2R_MPEG2_PADDING BIT(30) + #define S5P_FIMV_R2H_CMD_EMPTY 0 #define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 1 #define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 2 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index b1ad27b8515..0597b4d3a3f 100755 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -448,6 +448,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) { + unsigned int status; struct s5p_mfc_dev *dev; if (ctx == NULL) @@ -462,6 +463,10 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, dev); + status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) + & S5P_FIMV_DEC_STATUS_INTERLACE_MASK; + ctx->interlace = status == S5P_FIMV_DEC_STATUS_INTERLACE; + s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, @@ -709,7 +714,7 @@ static int s5p_mfc_open(struct file *file) ret = -ENOMEM; goto err_alloc; } - v4l2_fh_init(&ctx->fh, video_devdata(file)); + v4l2_fh_init(&ctx->fh, vdev); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); ctx->dev = dev; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index ab5ba6ea297..41474aa77cd 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -559,9 +559,12 @@ struct s5p_mfc_ctx { int img_height; int buf_width; int buf_height; + int interlace; int luma_size; int chroma_size; + int luma_size_to_report; + int chroma_size_to_report; int mv_size; unsigned long consumed_stream; @@ -604,9 +607,6 @@ struct s5p_mfc_ctx { struct s5p_mfc_enc_params enc_params; size_t enc_dst_buf_size; - size_t luma_dpb_size; - size_t chroma_dpb_size; - size_t me_buffer_size; size_t tmv_buffer_size; enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; @@ -681,4 +681,28 @@ void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); mem == V4L2_MEMORY_USERPTR || \ mem == V4L2_MEMORY_DMABUF) ? 1 : 0) +#define INITIAL_MAPPING_VAL ERR_PTR(-EAGAIN) + +static inline bool mfc_is_iommu_used(struct s5p_mfc_ctx *ctx) +{ +#ifdef CONFIG_ARM_DMA_USE_IOMMU + struct device *dev_iommu1 = ctx->dev->mem_dev_l; + struct device *dev_iommu2 = ctx->dev->mem_dev_r; + int iommu1_mapped, iommu2_mapped; + + iommu1_mapped = dev_iommu1->archdata.mapping && + dev_iommu1->archdata.mapping != INITIAL_MAPPING_VAL; + iommu2_mapped = dev_iommu2->archdata.mapping && + dev_iommu2->archdata.mapping != INITIAL_MAPPING_VAL; + + if (iommu1_mapped) { + /* Warn when one iommu is mapped and the second is not. + * This is a strange case. */ + WARN_ON(!iommu2_mapped); + return true; + } +#endif + return false; +} + #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index a428a972890..0e1830ef0f4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -50,7 +50,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER, &bank2_dma_addr, GFP_KERNEL); - if (IS_ERR(dev->fw_virt_addr)) { + if (IS_ERR(bank2_virt)) { mfc_err("Allocating bank2 base failed\n"); dma_free_coherent(dev->mem_dev_l, dev->fw_size, dev->fw_virt_addr, dev->bank1); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 58ec7bb26eb..5d5dde07d53 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -288,30 +288,48 @@ static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN); ctx->chroma_size = ALIGN(ctx->buf_width * - ALIGN((ctx->img_height >> 1), + ALIGN((ctx->buf_height >> 1), S5P_FIMV_NV12MT_VALIGN), S5P_FIMV_DEC_BUF_ALIGN); ctx->mv_size = ALIGN(ctx->buf_width * ALIGN((ctx->buf_height >> 2), S5P_FIMV_NV12MT_VALIGN), S5P_FIMV_DEC_BUF_ALIGN); + ctx->luma_size_to_report = ctx->luma_size; + ctx->chroma_size_to_report = ctx->chroma_size; } else { guard_width = - ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN); + ALIGN(ctx->buf_width + 24, S5P_FIMV_NV12MT_HALIGN); guard_height = - ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN); + ALIGN(ctx->buf_height + 16, S5P_FIMV_NV12MT_VALIGN); ctx->luma_size = ALIGN(guard_width * guard_height, S5P_FIMV_DEC_BUF_ALIGN); guard_width = - ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN); + ALIGN(ctx->buf_width + 16, S5P_FIMV_NV12MT_HALIGN); guard_height = - ALIGN((ctx->img_height >> 1) + 4, + ALIGN((ctx->buf_height >> 1) + 4, S5P_FIMV_NV12MT_VALIGN); ctx->chroma_size = ALIGN(guard_width * guard_height, S5P_FIMV_DEC_BUF_ALIGN); ctx->mv_size = 0; + + ctx->luma_size_to_report = ctx->luma_size; + ctx->chroma_size_to_report = ctx->chroma_size; + if (mfc_is_iommu_used(ctx)) { + ctx->luma_size_to_report *= 2; + ctx->chroma_size_to_report *= 2; + } + + /* If interlace is deteced for MPEG2 decoding the size of the + * luma an chroma buffers should be doubled */ + if (mfc_is_iommu_used(ctx) && ctx->interlace && ctx->codec_mode + == S5P_MFC_CODEC_MPEG2_DEC) + { + ctx->luma_size *= 2; + ctx->chroma_size *= 2; + } } } @@ -496,8 +514,8 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Not enough memory has been allocated\n"); return -ENOMEM; } - s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); - s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, ctx->luma_size_to_report, ALLOC_LUMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, ctx->chroma_size_to_report, ALLOC_CHROMA_DPB_SIZE); if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 66f0d042357..11828206c52 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -80,19 +80,19 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); - ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + ctx->luma_size = ALIGN((mb_width * mb_height) * S5P_FIMV_LUMA_MB_TO_PIXEL_V6, S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); - ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + ctx->chroma_size = ALIGN((mb_width * mb_height) * S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); - ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( + ctx->mv_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( ctx->img_width, ctx->img_height, mb_width, mb_height), S5P_FIMV_ME_BUFFER_ALIGN_V6); mfc_debug(2, "recon luma size: %d chroma size: %d\n", - ctx->luma_dpb_size, ctx->chroma_dpb_size); + ctx->luma_size, ctx->chroma_size); } else { return -EINVAL; } @@ -161,8 +161,8 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->pb_count * (ctx->luma_dpb_size + - ctx->chroma_dpb_size + ctx->me_buffer_size)); + (ctx->pb_count * (ctx->luma_size + + ctx->chroma_size + ctx->mv_size)); ctx->bank2.size = 0; break; case S5P_MFC_CODEC_MPEG4_ENC: @@ -175,8 +175,8 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->pb_count * (ctx->luma_dpb_size + - ctx->chroma_dpb_size + ctx->me_buffer_size)); + (ctx->pb_count * (ctx->luma_size + + ctx->chroma_size + ctx->mv_size)); ctx->bank2.size = 0; break; default: @@ -492,13 +492,13 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) for (i = 0; i < ctx->pb_count; i++) { WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i)); - buf_addr1 += ctx->luma_dpb_size; + buf_addr1 += ctx->luma_size; WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i)); - buf_addr1 += ctx->chroma_dpb_size; + buf_addr1 += ctx->chroma_size; WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER_V6 + (4 * i)); - buf_addr1 += ctx->me_buffer_size; - buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + - ctx->me_buffer_size); + buf_addr1 += ctx->mv_size; + buf_size1 -= (ctx->luma_size + ctx->chroma_size + + ctx->mv_size); } WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 436a0c19eb1..e23ccef80e0 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -191,6 +191,9 @@ static int max77686_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max77686_dev *max77686 = i2c_get_clientdata(i2c); + if (!max77686->irq) + return 0; + if (device_may_wakeup(dev)) enable_irq_wake(max77686->irq); @@ -208,6 +211,9 @@ static int max77686_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max77686_dev *max77686 = i2c_get_clientdata(i2c); + if (!max77686->irq) + return 0; + if (device_may_wakeup(dev)) disable_irq_wake(max77686->irq); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 9375b8c6410..7ce9b3fa1be 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1716,6 +1716,18 @@ static int smsc95xx_resume(struct usb_interface *intf) return ret; } +static int smsc95xx_reset_resume(struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + int ret; + + ret = smsc95xx_reset(dev); + if (ret < 0) + return ret; + + return smsc95xx_resume(intf); +} + static void smsc95xx_rx_csum_offload(struct sk_buff *skb) { skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); @@ -2006,7 +2018,7 @@ static struct usb_driver smsc95xx_driver = { .probe = usbnet_probe, .suspend = smsc95xx_suspend, .resume = smsc95xx_resume, - .reset_resume = smsc95xx_resume, + .reset_resume = smsc95xx_reset_resume, .disconnect = usbnet_disconnect, .disable_hub_initiated_lpm = 1, .supports_autosuspend = 1, diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c index 431568b5cc6..59d8dd3ff39 100644 --- a/drivers/phy/phy-exynos4x12-usb2.c +++ b/drivers/phy/phy-exynos4x12-usb2.c @@ -86,21 +86,23 @@ #define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1) #define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2) #define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3) +/* The following bit defines are presented in the + * order taken from the Exynos4412 reference manual. + * + * During experiments with the hardware and debugging + * it was determined that the hardware behaves contrary + * to the manual. + * + * The following bit values were chaned accordingly to the + * results of real hardware experiments. + */ #define EXYNOS_4x12_URSTCON_PHY1 BIT(4) -/* - * According to Exynos 4x12 reference manual the values for - * EXYNOS_4x12_URSTCON_HSIC are: - * URSTCON_HSIC0 = BIT(5) - * URSTCON_HSIC1 = BIT(6) - * but from experiments with real hardware the above 2 bitfields - * seems to be swapped, so define them to match the actual - * hardware */ -#define EXYNOS_4x12_URSTCON_HSIC1 BIT(5) #define EXYNOS_4x12_URSTCON_HSIC0 BIT(6) +#define EXYNOS_4x12_URSTCON_HSIC1 BIT(5) #define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7) -#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8) +#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(10) #define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9) -#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10) +#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(8) /* Isolation, configured in the power management unit */ #define EXYNOS_4x12_USB_ISOL_OFFSET 0x704 @@ -196,6 +198,7 @@ static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst) clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK); clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; + clk |= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON; writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK); } @@ -206,42 +209,31 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) u32 phypwr = 0; u32 rst; u32 pwr; - u32 mode = 0; - u32 switch_mode = 0; switch (inst->cfg->id) { case EXYNOS4x12_DEVICE: phypwr = EXYNOS_4x12_UPHYPWR_PHY0; rstbits = EXYNOS_4x12_URSTCON_PHY0; - mode = EXYNOS_4x12_MODE_SWITCH_DEVICE; - switch_mode = 1; break; case EXYNOS4x12_HOST: phypwr = EXYNOS_4x12_UPHYPWR_PHY1; - rstbits = EXYNOS_4x12_URSTCON_HOST_PHY; - mode = EXYNOS_4x12_MODE_SWITCH_HOST; - switch_mode = 1; + rstbits = EXYNOS_4x12_URSTCON_HOST_PHY | + EXYNOS_4x12_URSTCON_PHY1 | + EXYNOS_4x12_URSTCON_HOST_LINK_P0; break; case EXYNOS4x12_HSIC0: phypwr = EXYNOS_4x12_UPHYPWR_HSIC0; rstbits = EXYNOS_4x12_URSTCON_HSIC0 | - EXYNOS_4x12_URSTCON_HOST_LINK_P0 | - EXYNOS_4x12_URSTCON_HOST_PHY; + EXYNOS_4x12_URSTCON_HOST_LINK_P1 ; break; case EXYNOS4x12_HSIC1: phypwr = EXYNOS_4x12_UPHYPWR_HSIC1; rstbits = EXYNOS_4x12_URSTCON_HSIC1 | - EXYNOS_4x12_URSTCON_HOST_LINK_P1 | - EXYNOS_4x12_URSTCON_HOST_PHY; + EXYNOS_4x12_URSTCON_HOST_LINK_P1; break; }; if (on) { - if (switch_mode) - regmap_update_bits(drv->reg_sys, - EXYNOS_4x12_MODE_SWITCH_OFFSET, - EXYNOS_4x12_MODE_SWITCH_MASK, mode); - pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR); pwr &= ~phypwr; writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR); @@ -262,52 +254,78 @@ static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) } } -static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) +static void exynos4x12_power_on_internal(struct samsung_usb2_phy_instance *inst) { - struct samsung_usb2_phy_driver *drv = inst->drv; - struct samsung_usb2_phy_instance *device = - &drv->instances[EXYNOS4x12_DEVICE]; + if (inst->int_cnt++ > 0) + return; - inst->enabled++; exynos4x12_setup_clk(inst); - exynos4x12_phy_pwr(inst, 1); exynos4x12_isol(inst, 0); + exynos4x12_phy_pwr(inst, 1); +} + +static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) +{ + struct samsung_usb2_phy_driver *drv = inst->drv; + + if (inst->ext_cnt++ > 0) + return 0; + + if (inst->cfg->id == EXYNOS4x12_HOST) { + regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, + EXYNOS_4x12_MODE_SWITCH_MASK, + EXYNOS_4x12_MODE_SWITCH_HOST); + exynos4x12_power_on_internal(&drv->instances[EXYNOS4x12_DEVICE]); + } + + if (inst->cfg->id == EXYNOS4x12_DEVICE) + regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, + EXYNOS_4x12_MODE_SWITCH_MASK, + EXYNOS_4x12_MODE_SWITCH_DEVICE); - /* Power on the device, as it is necessary for HSIC to work */ if (inst->cfg->id == EXYNOS4x12_HSIC0 || - inst->cfg->id == EXYNOS4x12_HSIC1) { - if (!device->enabled) { - exynos4x12_phy_pwr(device, 1); - exynos4x12_isol(device, 0); - } - device->enabled++; + inst->cfg->id == EXYNOS4x12_HSIC1) { + exynos4x12_power_on_internal(&drv->instances[EXYNOS4x12_DEVICE]); + exynos4x12_power_on_internal(&drv->instances[EXYNOS4x12_HOST]); } + exynos4x12_power_on_internal(inst); + return 0; } +static void exynos4x12_power_off_internal(struct samsung_usb2_phy_instance *inst) +{ + if (inst->int_cnt-- > 1) + return; + + exynos4x12_isol(inst, 1); + exynos4x12_phy_pwr(inst, 0); +} + static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) { struct samsung_usb2_phy_driver *drv = inst->drv; - struct samsung_usb2_phy_instance *device = - &drv->instances[EXYNOS4x12_DEVICE]; - inst->enabled--; - if (inst->enabled) + if (inst->ext_cnt-- > 1) return 0; - exynos4x12_isol(inst, 1); - exynos4x12_phy_pwr(inst, 0); + if (inst->cfg->id == EXYNOS4x12_DEVICE) + regmap_update_bits(drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, + EXYNOS_4x12_MODE_SWITCH_MASK, + EXYNOS_4x12_MODE_SWITCH_HOST); + + if (inst->cfg->id == EXYNOS4x12_HOST) + exynos4x12_power_off_internal(&drv->instances[EXYNOS4x12_DEVICE]); if (inst->cfg->id == EXYNOS4x12_HSIC0 || - inst->cfg->id == EXYNOS4x12_HSIC1) { - device->enabled--; - if (!device->enabled) { - exynos4x12_isol(device, 1); - exynos4x12_phy_pwr(device, 0); - } + inst->cfg->id == EXYNOS4x12_HSIC1) { + exynos4x12_power_off_internal(&drv->instances[EXYNOS4x12_DEVICE]); + exynos4x12_power_off_internal(&drv->instances[EXYNOS4x12_HOST]); } + exynos4x12_power_off_internal(inst); + return 0; } diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h index 848744ab8f3..1cbdbf502a1 100644 --- a/drivers/phy/phy-samsung-usb2.h +++ b/drivers/phy/phy-samsung-usb2.h @@ -29,7 +29,8 @@ struct samsung_usb2_phy_instance { const struct samsung_usb2_common_phy *cfg; struct phy *phy; struct samsung_usb2_phy_driver *drv; - int enabled; + int int_cnt; + int ext_cnt; }; struct samsung_usb2_phy_driver { diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 1053eb651b2..31f7ebf5586 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -154,6 +154,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + /* USB3503 */ + { USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index ffc41e4bf65..20b372b5909 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -134,8 +134,8 @@ struct ffs_ep { struct usb_ep *ep; /* P: ffs->eps_lock */ struct usb_request *req; /* P: epfile->mutex */ - /* [0]: full speed, [1]: high speed */ - struct usb_endpoint_descriptor *descs[2]; + /* [0]: full speed, [1]: high speed, [2]: super speed */ + struct usb_endpoint_descriptor *descs[3]; u8 num; @@ -745,6 +745,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ struct usb_gadget *gadget = epfile->ffs->gadget; + spin_lock_irq(&epfile->ffs->eps_lock); + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + spin_unlock_irq(&epfile->ffs->eps_lock); + return -ESHUTDOWN; + } /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. @@ -752,6 +758,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = io_data->read ? usb_ep_align_maybe(gadget, ep->ep, io_data->len) : io_data->len; + spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) @@ -802,7 +809,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (io_data->aio) { req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); if (unlikely(!req)) - goto error; + goto error_lock; req->buf = data; req->length = io_data->len; @@ -817,7 +824,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); if (unlikely(ret)) { usb_ep_free_request(ep->ep, req); - goto error; + goto error_lock; } ret = -EIOCBQUEUED; @@ -843,19 +850,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ret = -EINTR; usb_ep_dequeue(ep->ep, req); } else { - /* - * XXX We may end up silently droping data here. - * Since data_len (i.e. req->length) may be bigger - * than len (after being rounded up to maxpacketsize), - * we may end up with more data then user space has - * space for. - */ - ret = ep->status; - if (io_data->read && ret > 0 && - unlikely(copy_to_user(io_data->buf, data, - min_t(size_t, ret, - io_data->len)))) - ret = -EFAULT; + /* + * XXX We may end up silently droping data + * here. Since data_len (i.e. req->length) may + * be bigger than len (after being rounded up + * to maxpacketsize), we may end up with more + * data then user space has space for. + */ + ret = ep->status; + if (io_data->read && ret > 0) { + ret = min_t(size_t, ret, io_data->len); + + if (unlikely(copy_to_user(io_data->buf, + data, ret))) + ret = -EFAULT; + } } kfree(data); } @@ -863,6 +872,10 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) mutex_unlock(&epfile->mutex); return ret; + +error_lock: + spin_unlock_irq(&epfile->ffs->eps_lock); + mutex_unlock(&epfile->mutex); error: kfree(data); return ret; @@ -915,7 +928,7 @@ ffs_epfile_open(struct inode *inode, struct file *file) return 0; } -static int ffs_aio_cancel(struct kiocb *kiocb) +static int ffs_aio_cancel(struct kiocb *kiocb, struct io_event *e) { struct ffs_io_data *io_data = kiocb->private; struct ffs_epfile *epfile = kiocb->ki_filp->private_data; @@ -1439,7 +1452,7 @@ static void ffs_data_clear(struct ffs_data *ffs) if (ffs->epfiles) ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); - kfree(ffs->raw_descs); + kfree(ffs->raw_descs_data); kfree(ffs->raw_strings); kfree(ffs->stringtabs); } @@ -1451,14 +1464,15 @@ static void ffs_data_reset(struct ffs_data *ffs) ffs_data_clear(ffs); ffs->epfiles = NULL; + ffs->raw_descs_data = NULL; ffs->raw_descs = NULL; ffs->raw_strings = NULL; ffs->stringtabs = NULL; ffs->raw_descs_length = 0; - ffs->raw_fs_descs_length = 0; ffs->fs_descs_count = 0; ffs->hs_descs_count = 0; + ffs->ss_descs_count = 0; ffs->strings_count = 0; ffs->interfaces_count = 0; @@ -1601,7 +1615,24 @@ static int ffs_func_eps_enable(struct ffs_function *func) spin_lock_irqsave(&func->ffs->eps_lock, flags); do { struct usb_endpoint_descriptor *ds; - ds = ep->descs[ep->descs[1] ? 1 : 0]; + int desc_idx; + + if (ffs->gadget->speed == USB_SPEED_SUPER) + desc_idx = 2; + else if (ffs->gadget->speed == USB_SPEED_HIGH) + desc_idx = 1; + else + desc_idx = 0; + + /* fall-back to lower speed if desc missing for current speed */ + do { + ds = ep->descs[desc_idx]; + } while (!ds && --desc_idx >= 0); + + if (!ds) { + ret = -EINVAL; + break; + } ep->ep->driver_data = ep; ep->ep->desc = ds; @@ -1736,6 +1767,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len, } break; + case USB_DT_SS_ENDPOINT_COMP: + pr_vdebug("EP SS companion descriptor\n"); + if (length != sizeof(struct usb_ss_ep_comp_descriptor)) + goto inv_length; + break; + case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_INTERFACE_POWER: case USB_DT_DEBUG: @@ -1846,60 +1883,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, static int __ffs_data_got_descs(struct ffs_data *ffs, char *const _data, size_t len) { - unsigned fs_count, hs_count; - int fs_len, ret = -EINVAL; - char *data = _data; + char *data = _data, *raw_descs; + unsigned counts[3], flags; + int ret = -EINVAL, i; ENTER(); - if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || - get_unaligned_le32(data + 4) != len)) + if (get_unaligned_le32(data + 4) != len) goto error; - fs_count = get_unaligned_le32(data + 8); - hs_count = get_unaligned_le32(data + 12); - if (!fs_count && !hs_count) - goto einval; - - data += 16; - len -= 16; - - if (likely(fs_count)) { - fs_len = ffs_do_descs(fs_count, data, len, - __ffs_data_do_entity, ffs); - if (unlikely(fs_len < 0)) { - ret = fs_len; + switch (get_unaligned_le32(data)) { + case FUNCTIONFS_DESCRIPTORS_MAGIC: + flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; + data += 8; + len -= 8; + break; + case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: + flags = get_unaligned_le32(data + 8); + if (flags & ~(FUNCTIONFS_HAS_FS_DESC | + FUNCTIONFS_HAS_HS_DESC | + FUNCTIONFS_HAS_SS_DESC)) { + ret = -ENOSYS; goto error; } + data += 12; + len -= 12; + break; + default: + goto error; + } - data += fs_len; - len -= fs_len; - } else { - fs_len = 0; + /* Read fs_count, hs_count and ss_count (if present) */ + for (i = 0; i < 3; ++i) { + if (!(flags & (1 << i))) { + counts[i] = 0; + } else if (len < 4) { + goto error; + } else { + counts[i] = get_unaligned_le32(data); + data += 4; + len -= 4; + } } - if (likely(hs_count)) { - ret = ffs_do_descs(hs_count, data, len, + /* Read descriptors */ + raw_descs = data; + for (i = 0; i < 3; ++i) { + if (!counts[i]) + continue; + ret = ffs_do_descs(counts[i], data, len, __ffs_data_do_entity, ffs); - if (unlikely(ret < 0)) + if (ret < 0) goto error; - } else { - ret = 0; + data += ret; + len -= ret; } - if (unlikely(len != ret)) - goto einval; + if (raw_descs == data || len) { + ret = -EINVAL; + goto error; + } - ffs->raw_fs_descs_length = fs_len; - ffs->raw_descs_length = fs_len + ret; - ffs->raw_descs = _data; - ffs->fs_descs_count = fs_count; - ffs->hs_descs_count = hs_count; + ffs->raw_descs_data = _data; + ffs->raw_descs = raw_descs; + ffs->raw_descs_length = data - raw_descs; + ffs->fs_descs_count = counts[0]; + ffs->hs_descs_count = counts[1]; + ffs->ss_descs_count = counts[2]; return 0; -einval: - ret = -EINVAL; error: kfree(_data); return ret; @@ -2117,21 +2170,28 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, struct usb_endpoint_descriptor *ds = (void *)desc; struct ffs_function *func = priv; struct ffs_ep *ffs_ep; - - /* - * If hs_descriptors is not NULL then we are reading hs - * descriptors now - */ - const int isHS = func->function.hs_descriptors != NULL; - unsigned idx; + unsigned ep_desc_id, idx; + static const char *speed_names[] = { "full", "high", "super" }; if (type != FFS_DESCRIPTOR) return 0; - if (isHS) + /* + * If ss_descriptors is not NULL, we are reading super speed + * descriptors; if hs_descriptors is not NULL, we are reading high + * speed descriptors; otherwise, we are reading full speed + * descriptors. + */ + if (func->function.ss_descriptors) { + ep_desc_id = 2; + func->function.ss_descriptors[(long)valuep] = desc; + } else if (func->function.hs_descriptors) { + ep_desc_id = 1; func->function.hs_descriptors[(long)valuep] = desc; - else + } else { + ep_desc_id = 0; func->function.fs_descriptors[(long)valuep] = desc; + } if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) return 0; @@ -2139,13 +2199,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; ffs_ep = func->eps + idx; - if (unlikely(ffs_ep->descs[isHS])) { - pr_vdebug("two %sspeed descriptors for EP %d\n", - isHS ? "high" : "full", + if (unlikely(ffs_ep->descs[ep_desc_id])) { + pr_err("two %sspeed descriptors for EP %d\n", + speed_names[ep_desc_id], ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); return -EINVAL; } - ffs_ep->descs[isHS] = ds; + ffs_ep->descs[ep_desc_id] = ds; ffs_dump_mem(": Original ep desc", ds, ds->bLength); if (ffs_ep->ep) { @@ -2289,8 +2349,10 @@ static int _ffs_func_bind(struct usb_configuration *c, const int full = !!func->ffs->fs_descs_count; const int high = gadget_is_dualspeed(func->gadget) && func->ffs->hs_descs_count; + const int super = gadget_is_superspeed(func->gadget) && + func->ffs->ss_descs_count; - int ret; + int fs_len, hs_len, ret; /* Make it a single chunk, less management later on */ vla_group(d); @@ -2299,15 +2361,16 @@ static int _ffs_func_bind(struct usb_configuration *c, full ? ffs->fs_descs_count + 1 : 0); vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, high ? ffs->hs_descs_count + 1 : 0); + vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, + super ? ffs->ss_descs_count + 1 : 0); vla_item_with_sz(d, short, inums, ffs->interfaces_count); - vla_item_with_sz(d, char, raw_descs, - high ? ffs->raw_descs_length : ffs->raw_fs_descs_length); + vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; ENTER(); - /* Only high speed but not supported by gadget? */ - if (unlikely(!(full | high))) + /* Has descriptors only for speeds gadget does not support */ + if (unlikely(!(full | high | super))) return -ENOTSUPP; /* Allocate a single chunk, less management later on */ @@ -2317,8 +2380,10 @@ static int _ffs_func_bind(struct usb_configuration *c, /* Zero */ memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); - memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16, - d_raw_descs__sz); + /* Copy descriptors */ + memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, + ffs->raw_descs_length); + memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); for (ret = ffs->eps_count; ret; --ret) { struct ffs_ep *ptr; @@ -2340,22 +2405,38 @@ static int _ffs_func_bind(struct usb_configuration *c, */ if (likely(full)) { func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); - ret = ffs_do_descs(ffs->fs_descs_count, - vla_ptr(vlabuf, d, raw_descs), - d_raw_descs__sz, - __ffs_func_bind_do_descs, func); - if (unlikely(ret < 0)) + fs_len = ffs_do_descs(ffs->fs_descs_count, + vla_ptr(vlabuf, d, raw_descs), + d_raw_descs__sz, + __ffs_func_bind_do_descs, func); + if (unlikely(fs_len < 0)) { + ret = fs_len; goto error; + } } else { - ret = 0; + fs_len = 0; } if (likely(high)) { func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); - ret = ffs_do_descs(ffs->hs_descs_count, - vla_ptr(vlabuf, d, raw_descs) + ret, - d_raw_descs__sz - ret, - __ffs_func_bind_do_descs, func); + hs_len = ffs_do_descs(ffs->hs_descs_count, + vla_ptr(vlabuf, d, raw_descs) + fs_len, + d_raw_descs__sz - fs_len, + __ffs_func_bind_do_descs, func); + if (unlikely(hs_len < 0)) { + ret = hs_len; + goto error; + } + } else { + hs_len = 0; + } + + if (likely(super)) { + func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); + ret = ffs_do_descs(ffs->ss_descs_count, + vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, + d_raw_descs__sz - fs_len - hs_len, + __ffs_func_bind_do_descs, func); if (unlikely(ret < 0)) goto error; } @@ -2366,7 +2447,8 @@ static int _ffs_func_bind(struct usb_configuration *c, * now. */ ret = ffs_do_descs(ffs->fs_descs_count + - (high ? ffs->hs_descs_count : 0), + (high ? ffs->hs_descs_count : 0) + + (super ? ffs->ss_descs_count : 0), vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, __ffs_func_bind_do_nums, func); if (unlikely(ret < 0)) @@ -2713,6 +2795,7 @@ static void ffs_func_unbind(struct usb_configuration *c, */ func->function.fs_descriptors = NULL; func->function.hs_descriptors = NULL; + func->function.ss_descriptors = NULL; func->interfaces_nums = NULL; ffs_event_add(ffs, FUNCTIONFS_UNBIND); diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 6e4aefe1c0c..2cd3fc394d0 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -383,6 +383,7 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) dev_err(hsotg->dev, "%s: timeout flushing fifos (GRSTCTL=%08x)\n", __func__, val); + break; } udelay(1); @@ -1791,6 +1792,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) dev_err(hsotg->dev, "%s: timeout flushing fifo (GRSTCTL=%08x)\n", __func__, val); + break; } udelay(1); @@ -3548,13 +3550,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev) hsotg->irq = ret; - ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0, - dev_name(dev), hsotg); - if (ret < 0) { - dev_err(dev, "cannot claim IRQ\n"); - goto err_clk; - } - dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); hsotg->gadget.max_speed = USB_SPEED_HIGH; @@ -3594,6 +3589,17 @@ static int s3c_hsotg_probe(struct platform_device *pdev) s3c_hsotg_init(hsotg); s3c_hsotg_hw_cfg(hsotg); + ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0, + dev_name(dev), hsotg); + if (ret < 0) { + s3c_hsotg_phy_disable(hsotg); + clk_disable_unprepare(hsotg->clk); + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + dev_err(dev, "cannot claim IRQ\n"); + goto err_clk; + } + /* hsotg->num_of_eps holds number of EPs other than ep0 */ if (hsotg->num_of_eps == 0) { diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index c39e805025b..bf0ba375d45 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -206,16 +206,16 @@ struct ffs_data { /* filled by __ffs_data_got_descs() */ /* - * Real descriptors are 16 bytes after raw_descs (so you need - * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the - * first full speed descriptor). raw_descs_length and - * raw_fs_descs_length do not have those 16 bytes added. + * raw_descs is what you kfree, real_descs points inside of raw_descs, + * where full speed, high speed and super speed descriptors start. + * real_descs_length is the length of all those descriptors. */ + const void *raw_descs_data; const void *raw_descs; unsigned raw_descs_length; - unsigned raw_fs_descs_length; unsigned fs_descs_count; unsigned hs_descs_count; + unsigned ss_descs_count; unsigned short strings_count; unsigned short interfaces_count; diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index bdd7336a6b4..e7ab8c98714 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -376,6 +376,8 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri udc->gadget->dev.driver = &driver->driver; node = udc->gadget->dev.of_node; + + edev = 0; /* Check if we have an extcon associated with the UDC driver */ if (node && of_property_read_bool(node, "extcon")) { edev = extcon_get_edev_by_phandle(&udc->gadget->dev, 0); @@ -402,20 +404,25 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri ret = driver->bind(udc->gadget, driver); if (ret) goto err2; - ret = usb_gadget_udc_start(udc->gadget, driver); - if (ret) { - driver->unbind(udc->gadget); - goto err2; - } - - usb_gadget_connect(udc->gadget); if (udc->extcon_usb_dev.edev) { - udc->enabled = 1; + udc->enabled = 0; udc->cable_state = extcon_get_cable_state_( udc->extcon_usb_dev.edev, udc->extcon_usb_dev.cable_index); - queue_work(udc->pwr_workqueue, &udc->pwr_work); + } else { + udc->cable_state = 1; + } + + if (udc->cable_state) { + ret = usb_gadget_udc_start(udc->gadget, driver); + if (ret) { + driver->unbind(udc->gadget); + goto err2; + } + + usb_gadget_connect(udc->gadget); + udc->enabled = 1; } kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index cd1282443c8..8b14ac5d786 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -424,7 +424,7 @@ static int s5p_ehci_resume(struct device *dev) /* DMA burst Enable */ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - ehci_resume(hcd, false); + ehci_resume(hcd, true); return 0; } #else diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index b0b542c14e3..da063718290 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -15,9 +15,12 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/platform_data/usb-ohci-exynos.h> +#include <linux/phy/phy.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> +#define PHY_NUMBER 3 + struct exynos_ohci_hcd { struct device *dev; struct usb_hcd *hcd; @@ -25,26 +28,106 @@ struct exynos_ohci_hcd { struct usb_phy *phy; struct usb_otg *otg; struct exynos4_ohci_platdata *pdata; + struct phy *phy_g[PHY_NUMBER]; }; -static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) +static int exynos_ohci_get_phy(struct device *dev, + struct exynos_ohci_hcd *exynos_ohci) +{ + struct device_node *child; + struct phy *phy; + int phy_number; + int ret = 0; + + exynos_ohci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(exynos_ohci->phy)) { + ret = PTR_ERR(exynos_ohci->phy); + if (ret != -ENXIO && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } else { + exynos_ohci->otg = exynos_ohci->phy->otg; + } + + /* + * Getting generic phy: + * We are keeping both types of phys as a part of transiting OHCI + * to generic phy framework, so as to maintain backward compatibilty + * with old DTB. + * If there are existing devices using DTB files built from them, + * to remove the support for old bindings in this driver, + * we need to make sure that such devices have their DTBs + * updated to ones built from new DTS. + */ + for_each_available_child_of_node(dev->of_node, child) { + ret = of_property_read_u32(child, "reg", &phy_number); + if (ret) { + dev_err(dev, "Failed to parse device tree\n"); + of_node_put(child); + return ret; + } + + if (phy_number >= PHY_NUMBER) { + dev_err(dev, "Invalid number of PHYs\n"); + of_node_put(child); + return -EINVAL; + } + + phy = devm_of_phy_get(dev, child, 0); + of_node_put(child); + if (IS_ERR(phy)) { + ret = PTR_ERR(phy); + if (ret != -ENOSYS && ret != -ENODEV) { + dev_err(dev, "no usb2 phy configured\n"); + return ret; + } + dev_dbg(dev, "Failed to get usb2 phy\n"); + } + exynos_ohci->phy_g[phy_number] = phy; + } + + return ret; +} + +static int exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) { struct platform_device *pdev = to_platform_device(exynos_ohci->dev); + int i; + int ret = 0; - if (exynos_ohci->phy) - usb_phy_init(exynos_ohci->phy); + if (!IS_ERR(exynos_ohci->phy)) + return usb_phy_init(exynos_ohci->phy); else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init) exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); + else { + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ohci->phy_g[i])) + ret = phy_power_on(exynos_ohci->phy_g[i]); + if (ret) + for (i--; i >= 0; i--) + if (!IS_ERR(exynos_ohci->phy_g[i])) + phy_power_off(exynos_ohci->phy_g[i]); + } + + return ret; } static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) { struct platform_device *pdev = to_platform_device(exynos_ohci->dev); + int i; - if (exynos_ohci->phy) + if (!IS_ERR(exynos_ohci->phy)) usb_phy_shutdown(exynos_ohci->phy); else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit) exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); + else { + for (i = 0; i < PHY_NUMBER; i++) + if (!IS_ERR(exynos_ohci->phy_g[i])) + phy_power_off(exynos_ohci->phy_g[i]); + } } static int ohci_exynos_reset(struct usb_hcd *hcd) @@ -105,7 +188,6 @@ static int exynos_ohci_probe(struct platform_device *pdev) struct usb_hcd *hcd; struct ohci_hcd *ohci; struct resource *res; - struct usb_phy *phy; int irq; int err; @@ -128,8 +210,8 @@ static int exynos_ohci_probe(struct platform_device *pdev) "samsung,exynos5440-ohci")) goto skip_phy; - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR(phy)) { + err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); + if (err) { /* Fallback to pdata */ if (!pdata) { dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); @@ -137,9 +219,6 @@ static int exynos_ohci_probe(struct platform_device *pdev) } else { exynos_ohci->pdata = pdata; } - } else { - exynos_ohci->phy = phy; - exynos_ohci->otg = phy->otg; } skip_phy: @@ -193,10 +272,15 @@ skip_phy: exynos_ohci->otg->set_host(exynos_ohci->otg, &exynos_ohci->hcd->self); - exynos_ohci_phy_enable(exynos_ohci); + platform_set_drvdata(pdev, hcd); ohci = hcd_to_ohci(hcd); ohci_hcd_init(ohci); + err = exynos_ohci_phy_enable(exynos_ohci); + if (err) { + dev_err(&pdev->dev, "Failed to enable USB phy\n"); + goto fail_io; + } err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { @@ -288,6 +372,7 @@ 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; + int ret; clk_prepare_enable(exynos_ohci->clk); @@ -295,7 +380,12 @@ static int exynos_ohci_resume(struct device *dev) exynos_ohci->otg->set_host(exynos_ohci->otg, &exynos_ohci->hcd->self); - exynos_ohci_phy_enable(exynos_ohci); + ret = exynos_ohci_phy_enable(exynos_ohci); + if (ret) { + dev_err(dev, "Failed to enable USB phy\n"); + clk_disable_unprepare(exynos_ohci->clk); + return ret; + } ohci_resume(hcd, false); diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 52cb7549b77..47cb143716a 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -149,8 +149,6 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) case USB3503_MODE_STANDBY: usb3503_reset(hub, 0); - - hub->mode = mode; dev_info(dev, "switched to STANDBY mode\n"); break; @@ -187,25 +185,57 @@ static int usb3503_probe(struct usb3503 *hub) hub->gpio_reset = pdata->gpio_reset; hub->mode = pdata->initial_mode; } else if (np) { + struct clk *clk; hub->port_off_mask = 0; - hub->clk = devm_clk_get(dev, "refclk"); - if (!IS_ERR(hub->clk)) { - unsigned long rate; + clk = devm_clk_get(dev, "refclk"); + if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT) { + dev_err(dev, "unable to request refclk (%ld)\n", + PTR_ERR(clk)); + return PTR_ERR(clk); + } - clk_prepare_enable(hub->clk); - rate = clk_get_rate(hub->clk); + if (!IS_ERR(clk)) { + u32 rate = 0; + hub->clk = clk; + + if (!of_property_read_u32(np, "refclk-frequency", + &rate)) { + + switch (rate) { + case 38400000: + case 26000000: + case 19200000: + case 12000000: + hub->secondary_ref_clk = 0; + break; + case 24000000: + case 27000000: + case 25000000: + case 50000000: + hub->secondary_ref_clk = 1; + break; + default: + dev_err(dev, + "unsupported reference clock rate (%d)\n", + (int) rate); + return -EINVAL; + } + err = clk_set_rate(hub->clk, rate); + if (err) { + dev_err(dev, + "unable to set reference clock rate to %d\n", + (int) rate); + return err; + } + } - if (rate == 38400000 || rate == 26000000 || - rate == 19200000 || rate == 12000000) - hub->secondary_ref_clk = 0; - else if (rate == 24000000 || rate == 27000000 || - rate == 25000000 || rate == 50000000) - hub->secondary_ref_clk = 1; - else + err = clk_prepare_enable(hub->clk); + if (err) { dev_err(dev, - "unsupported reference clock rate (%d)\n", - rate); + "unable to enable reference clock\n"); + return err; + } } property = of_get_property(np, "disabled-ports", &len); @@ -315,6 +345,37 @@ static int usb3503_platform_probe(struct platform_device *pdev) return usb3503_probe(hub); } +#ifdef CONFIG_PM_SLEEP +static int usb3503_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb3503 *hub = i2c_get_clientdata(client); + + usb3503_switch_mode(hub, USB3503_MODE_STANDBY); + + if (hub->clk) + clk_disable_unprepare(hub->clk); + + return 0; +} + +static int usb3503_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb3503 *hub = i2c_get_clientdata(client); + + if (hub->clk) + clk_prepare_enable(hub->clk); + + usb3503_switch_mode(hub, hub->mode); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(usb3503_i2c_pm_ops, usb3503_i2c_suspend, + usb3503_i2c_resume); + static const struct i2c_device_id usb3503_id[] = { { USB3503_I2C_NAME, 0 }, { } @@ -333,6 +394,7 @@ MODULE_DEVICE_TABLE(of, usb3503_of_match); static struct i2c_driver usb3503_i2c_driver = { .driver = { .name = USB3503_I2C_NAME, + .pm = &usb3503_i2c_pm_ops, .of_match_table = of_match_ptr(usb3503_of_match), }, .probe = usb3503_i2c_probe, diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 7209df15a3c..f6d4c851c5b 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -49,6 +49,13 @@ struct mipi_dsi_msg { * @detach: detach DSI device from DSI host * @transfer: send and/or receive DSI packet, return number of received bytes, * or error + * @te_handler: call the crtc te_handler() callback from DSI host. + * The panel generates tearing effect synchronization signal + * between MCU and FB to display video images. + * And the display controller should trigger to transfer video + * image at this signal. + * So the panel receives the TE IRQ, then calls this handler + * to notify it to the display controller. */ struct mipi_dsi_host_ops { int (*attach)(struct mipi_dsi_host *host, @@ -57,6 +64,7 @@ struct mipi_dsi_host_ops { struct mipi_dsi_device *dsi); ssize_t (*transfer)(struct mipi_dsi_host *host, struct mipi_dsi_msg *msg); + int (*te_handler)(struct mipi_dsi_host *host); }; /** diff --git a/include/uapi/linux/netfilter/Kbuild b/include/uapi/linux/netfilter/Kbuild index 41115776d76..7620b8399f7 100644 --- a/include/uapi/linux/netfilter/Kbuild +++ b/include/uapi/linux/netfilter/Kbuild @@ -36,6 +36,7 @@ header-y += xt_TEE.h header-y += xt_TPROXY.h header-y += xt_addrtype.h header-y += xt_bpf.h +header-y += xt_cgroup.h header-y += xt_cluster.h header-y += xt_comment.h header-y += xt_connbytes.h diff --git a/include/uapi/linux/netfilter/xt_cgroup.h b/include/uapi/linux/netfilter/xt_cgroup.h new file mode 100644 index 00000000000..43acb7e175f --- /dev/null +++ b/include/uapi/linux/netfilter/xt_cgroup.h @@ -0,0 +1,11 @@ +#ifndef _UAPI_XT_CGROUP_H +#define _UAPI_XT_CGROUP_H + +#include <linux/types.h> + +struct xt_cgroup_info { + __u32 id; + __u32 invert; +}; + +#endif /* _UAPI_XT_CGROUP_H */ diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index d6b01283f85..24b68c59dcf 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -10,9 +10,15 @@ enum { FUNCTIONFS_DESCRIPTORS_MAGIC = 1, - FUNCTIONFS_STRINGS_MAGIC = 2 + FUNCTIONFS_STRINGS_MAGIC = 2, + FUNCTIONFS_DESCRIPTORS_MAGIC_V2 = 3, }; +enum functionfs_flags { + FUNCTIONFS_HAS_FS_DESC = 1, + FUNCTIONFS_HAS_HS_DESC = 2, + FUNCTIONFS_HAS_SS_DESC = 4, +}; #ifndef __KERNEL__ @@ -27,31 +33,48 @@ struct usb_endpoint_descriptor_no_audio { __u8 bInterval; } __attribute__((packed)); - -/* - * All numbers must be in little endian order. - */ - +/* Legacy format, deprecated as of 3.14. */ struct usb_functionfs_descs_head { __le32 magic; __le32 length; __le32 fs_count; __le32 hs_count; -} __attribute__((packed)); +} __attribute__((packed, deprecated)); /* * Descriptors format: * * | off | name | type | description | * |-----+-----------+--------------+--------------------------------------| - * | 0 | magic | LE32 | FUNCTIONFS_{FS,HS}_DESCRIPTORS_MAGIC | + * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 | + * | 4 | length | LE32 | length of the whole data chunk | + * | 8 | flags | LE32 | combination of functionfs_flags | + * | | fs_count | LE32 | number of full-speed descriptors | + * | | hs_count | LE32 | number of high-speed descriptors | + * | | ss_count | LE32 | number of super-speed descriptors | + * | | fs_descrs | Descriptor[] | list of full-speed descriptors | + * | | hs_descrs | Descriptor[] | list of high-speed descriptors | + * | | ss_descrs | Descriptor[] | list of super-speed descriptors | + * + * Depending on which flags are set, various fields may be missing in the + * structure. Any flags that are not recognised cause the whole block to be + * rejected with -ENOSYS. + * + * Legacy descriptors format: + * + * | off | name | type | description | + * |-----+-----------+--------------+--------------------------------------| + * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC | * | 4 | length | LE32 | length of the whole data chunk | * | 8 | fs_count | LE32 | number of full-speed descriptors | * | 12 | hs_count | LE32 | number of high-speed descriptors | * | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors | * | | hs_descrs | Descriptor[] | list of high-speed descriptors | * - * descs are just valid USB descriptors and have the following format: + * All numbers must be in little endian order. + * + * Descriptor[] is an array of valid USB descriptors which have the following + * format: * * | off | name | type | description | * |-----+-----------------+------+--------------------------| diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index b0393209679..eaad58b5be4 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h @@ -19,6 +19,7 @@ /* VIDCON0 */ #define VIDCON0 0x00 +#define VIDCON0_DSI_EN (1 << 30) #define VIDCON0_INTERLACE (1 << 29) #define VIDCON0_VIDOUT_MASK (0x7 << 26) #define VIDCON0_VIDOUT_SHIFT 26 @@ -355,7 +356,7 @@ #define VIDINTCON0_INT_ENABLE (1 << 0) #define VIDINTCON1 0x134 -#define VIDINTCON1_INT_I180 (1 << 2) +#define VIDINTCON1_INT_I80 (1 << 2) #define VIDINTCON1_INT_FRAME (1 << 1) #define VIDINTCON1_INT_FIFO (1 << 0) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 56d22cae590..1f63a3bf866 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -814,6 +814,16 @@ config NETFILTER_XT_MATCH_BPF To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_CGROUP + tristate '"control group" match support' + depends on NETFILTER_ADVANCED + depends on CGROUPS + select CGROUP_NET_CLASSID + ---help--- + Socket/process control group matching allows you to match locally + generated packets based on which net_cls control group processes + belong to. + config NETFILTER_XT_MATCH_CLUSTER tristate '"cluster" match support' depends on NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a1abf87d43b..736dc1029af 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o obj-$(CONFIG_NETFILTER_XT_MATCH_NFACCT) += xt_nfacct.o obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o +obj-$(CONFIG_NETFILTER_XT_MATCH_CGROUP) += xt_cgroup.o obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o diff --git a/net/netfilter/xt_cgroup.c b/net/netfilter/xt_cgroup.c new file mode 100644 index 00000000000..9a8e77e7f8d --- /dev/null +++ b/net/netfilter/xt_cgroup.c @@ -0,0 +1,71 @@ +/* + * Xtables module to match the process control group. + * + * Might be used to implement individual "per-application" firewall + * policies in contrast to global policies based on control groups. + * Matching is based upon processes tagged to net_cls' classid marker. + * + * (C) 2013 Daniel Borkmann <dborkman@redhat.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. + */ + +#include <linux/skbuff.h> +#include <linux/module.h> +#include <linux/netfilter/x_tables.h> +#include <linux/netfilter/xt_cgroup.h> +#include <net/sock.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); +MODULE_DESCRIPTION("Xtables: process control group matching"); +MODULE_ALIAS("ipt_cgroup"); +MODULE_ALIAS("ip6t_cgroup"); + +static int cgroup_mt_check(const struct xt_mtchk_param *par) +{ + struct xt_cgroup_info *info = par->matchinfo; + + if (info->invert & ~1) + return -EINVAL; + + return info->id ? 0 : -EINVAL; +} + +static bool +cgroup_mt(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_cgroup_info *info = par->matchinfo; + + if (skb->sk == NULL) + return false; + + return (info->id == skb->sk->sk_classid) ^ info->invert; +} + +static struct xt_match cgroup_mt_reg __read_mostly = { + .name = "cgroup", + .revision = 0, + .family = NFPROTO_UNSPEC, + .checkentry = cgroup_mt_check, + .match = cgroup_mt, + .matchsize = sizeof(struct xt_cgroup_info), + .me = THIS_MODULE, + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING), +}; + +static int __init cgroup_mt_init(void) +{ + return xt_register_match(&cgroup_mt_reg); +} + +static void __exit cgroup_mt_exit(void) +{ + xt_unregister_match(&cgroup_mt_reg); +} + +module_init(cgroup_mt_init); +module_exit(cgroup_mt_exit); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 8bbd79490b8..7f9719af275 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -3,6 +3,7 @@ config SND_SOC_SAMSUNG depends on PLAT_SAMSUNG select S3C64XX_DMA if ARCH_S3C64XX select S3C2410_DMA if ARCH_S3C24XX + select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to the Samsung SoCs' Audio interfaces. You will also need to @@ -233,13 +234,13 @@ config SND_SOC_LITTLEMILL select MFD_WM8994 select SND_SOC_WM8994 -config SND_SOC_SAMSUNG_EXYNOS4_WM1811 - tristate "SoC I2S Audio support for WM1811 on Tizen Exynos4 board" +config SND_SOC_SAMSUNG_TRATS2_WM1811 + tristate "SoC I2S Audio support for WM1811 on Tizen Trats2 board" depends on SND_SOC_SAMSUNG select SND_SOC_WM8994 select SND_SAMSUNG_I2S help - Say Y if you want to add support for SoC audio on the Tizen Exynos4 board. + Say Y if you want to add support for SoC audio on the Tizen Trats2 board. config SND_SOC_ODROIDX2 tristate "Audio support for Odroidx2" diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 8a675f18d98..da223de7557 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -44,7 +44,7 @@ snd-soc-trats-objs := trats_mc1n2.o snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o -snd-soc-exynos4-wm1811-objs := exynos4_wm1811.o +snd-soc-trats2-wm1811-objs := trats2_wm1811.o snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o @@ -71,5 +71,5 @@ obj-$(CONFIG_SND_SOC_TRATS) += snd-soc-trats.o obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o -obj-$(CONFIG_SND_SOC_SAMSUNG_EXYNOS4_WM1811) += snd-soc-exynos4-wm1811.o +obj-$(CONFIG_SND_SOC_SAMSUNG_TRATS2_WM1811) += snd-soc-trats2-wm1811.o obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 6e2b2b4dca5..26db25da19c 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -20,6 +20,9 @@ #include <sound/soc.h> #include <sound/pcm_params.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/dmaengine_pcm.h> #include <asm/dma.h> #include <mach/hardware.h> @@ -27,14 +30,13 @@ #include "dma.h" -#define ST_RUNNING (1<<0) -#define ST_OPENED (1<<1) - static const struct snd_pcm_hardware dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U8 | @@ -49,290 +51,77 @@ static const struct snd_pcm_hardware dma_hardware = { .fifo_size = 32, }; -struct runtime_data { - spinlock_t lock; - int state; - unsigned int dma_loaded; - unsigned int dma_period; - dma_addr_t dma_start; - dma_addr_t dma_pos; - dma_addr_t dma_end; - struct s3c_dma_params *params; -}; - -static void audio_buffdone(void *data); - -/* dma_enqueue - * - * place a dma buffer onto the queue for the dma system - * to handle. - */ -static void dma_enqueue(struct snd_pcm_substream *substream) -{ - struct runtime_data *prtd = substream->runtime->private_data; - dma_addr_t pos = prtd->dma_pos; - unsigned int limit; - struct samsung_dma_prep dma_info; - - pr_debug("Entered %s\n", __func__); - - limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; - - pr_debug("%s: loaded %d, limit %d\n", - __func__, prtd->dma_loaded, limit); - - dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); - dma_info.direction = - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); - dma_info.fp = audio_buffdone; - dma_info.fp_param = substream; - dma_info.period = prtd->dma_period; - dma_info.len = prtd->dma_period*limit; - - if (dma_info.cap == DMA_CYCLIC) { - dma_info.buf = pos; - prtd->params->ops->prepare(prtd->params->ch, &dma_info); - prtd->dma_loaded += limit; - return; - } - - while (prtd->dma_loaded < limit) { - pr_debug("dma_loaded: %d\n", prtd->dma_loaded); - - if ((pos + dma_info.period) > prtd->dma_end) { - dma_info.period = prtd->dma_end - pos; - pr_debug("%s: corrected dma len %ld\n", - __func__, dma_info.period); - } - - dma_info.buf = pos; - prtd->params->ops->prepare(prtd->params->ch, &dma_info); - - prtd->dma_loaded++; - pos += prtd->dma_period; - if (pos >= prtd->dma_end) - pos = prtd->dma_start; - } - - prtd->dma_pos = pos; -} - -static void audio_buffdone(void *data) -{ - struct snd_pcm_substream *substream = data; - struct runtime_data *prtd = substream->runtime->private_data; - - pr_debug("Entered %s\n", __func__); - - if (prtd->state & ST_RUNNING) { - prtd->dma_pos += prtd->dma_period; - if (prtd->dma_pos >= prtd->dma_end) - prtd->dma_pos = prtd->dma_start; - - if (substream) - snd_pcm_period_elapsed(substream); - - spin_lock(&prtd->lock); - if (!samsung_dma_has_circular()) { - prtd->dma_loaded--; - dma_enqueue(substream); - } - spin_unlock(&prtd->lock); - } -} - +/* This might get called for several times by oss emulation */ static int dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - unsigned long totbytes = params_buffer_bytes(params); - struct s3c_dma_params *dma = - snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - struct samsung_dma_req req; - struct samsung_dma_config config; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dmaengine_dai_dma_data *dma; + struct dma_slave_config slave_config; + struct dma_chan *chan; + int ret; pr_debug("Entered %s\n", __func__); + dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma) return 0; - /* this may get called several times by oss emulation - * with different params -HW */ - if (prtd->params == NULL) { - /* prepare DMA */ - prtd->params = dma; - - pr_debug("params %p, client %p, channel %d\n", prtd->params, - prtd->params->client, prtd->params->channel); - - prtd->params->ops = samsung_dma_get_ops(); - - req.cap = (samsung_dma_has_circular() ? - DMA_CYCLIC : DMA_SLAVE); - req.client = prtd->params->client; - config.direction = - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); - config.width = prtd->params->dma_size; - config.fifo = prtd->params->dma_addr; - prtd->params->ch = prtd->params->ops->request( - prtd->params->channel, &req, rtd->cpu_dai->dev, - prtd->params->ch_name); - prtd->params->ops->config(prtd->params->ch, &config); - } - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); - runtime->dma_bytes = totbytes; + chan = snd_dmaengine_pcm_get_chan(substream); + if (!chan) + return -ENODEV; - spin_lock_irq(&prtd->lock); - prtd->dma_loaded = 0; - prtd->dma_period = params_period_bytes(params); - prtd->dma_start = runtime->dma_addr; - prtd->dma_pos = prtd->dma_start; - prtd->dma_end = prtd->dma_start + totbytes; - spin_unlock_irq(&prtd->lock); + ret = snd_dmaengine_pcm_prepare_slave_config(substream, params, + &slave_config); + if (ret) + return ret; - return 0; + return dmaengine_slave_config(chan, &slave_config); } static int dma_hw_free(struct snd_pcm_substream *substream) { - struct runtime_data *prtd = substream->runtime->private_data; - pr_debug("Entered %s\n", __func__); snd_pcm_set_runtime_buffer(substream, NULL); - if (prtd->params) { - prtd->params->ops->flush(prtd->params->ch); - prtd->params->ops->release(prtd->params->ch, - prtd->params->client); - prtd->params = NULL; - } - return 0; } -static int dma_prepare(struct snd_pcm_substream *substream) -{ - struct runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!prtd->params) - return 0; - - /* flush the DMA channel */ - prtd->params->ops->flush(prtd->params->ch); - - prtd->dma_loaded = 0; - prtd->dma_pos = prtd->dma_start; - - /* enqueue dma buffers */ - dma_enqueue(substream); - - return ret; -} - -static int dma_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - spin_lock(&prtd->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->state |= ST_RUNNING; - prtd->params->ops->trigger(prtd->params->ch); - break; - - case SNDRV_PCM_TRIGGER_STOP: - prtd->state &= ~ST_RUNNING; - prtd->params->ops->stop(prtd->params->ch); - break; - - default: - ret = -EINVAL; - break; - } - - spin_unlock(&prtd->lock); - - return ret; -} - -static snd_pcm_uframes_t -dma_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct runtime_data *prtd = runtime->private_data; - unsigned long res; - - pr_debug("Entered %s\n", __func__); - - res = prtd->dma_pos - prtd->dma_start; - - pr_debug("Pointer offset: %lu\n", res); - - /* we seem to be getting the odd error from the pcm library due - * to out-of-bounds pointers. this is maybe due to the dma engine - * not having loaded the new values for the channel before being - * called... (todo - fix ) - */ - - if (res >= snd_pcm_lib_buffer_bytes(substream)) { - if (res == snd_pcm_lib_buffer_bytes(substream)) - res = 0; - } - - return bytes_to_frames(substream->runtime, res); -} +static const char * const dma_chan_names[] = { + [SNDRV_PCM_STREAM_PLAYBACK] = "tx", + [SNDRV_PCM_STREAM_CAPTURE] = "rx", +}; static int dma_open(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct runtime_data *prtd; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dma_chan *chan; pr_debug("Entered %s\n", __func__); - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); snd_soc_set_runtime_hwparams(substream, &dma_hardware); - prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL); - if (prtd == NULL) + chan = kzalloc(sizeof(struct dma_chan), GFP_KERNEL); + if (!chan) return -ENOMEM; - spin_lock_init(&prtd->lock); + /* Request slave dma channel according to playback/capture stream */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + chan = dma_request_slave_channel(rtd->cpu_dai->dev, + dma_chan_names[0]); + else + chan = dma_request_slave_channel(rtd->cpu_dai->dev, + dma_chan_names[1]); - runtime->private_data = prtd; - return 0; -} - -static int dma_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct runtime_data *prtd = runtime->private_data; - - pr_debug("Entered %s\n", __func__); - - if (!prtd) - pr_debug("dma_close called with prtd == NULL\n"); - - kfree(prtd); - - return 0; + return snd_dmaengine_pcm_open(substream, chan); } static int dma_mmap(struct snd_pcm_substream *substream, @@ -350,13 +139,12 @@ static int dma_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops dma_ops = { .open = dma_open, - .close = dma_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = dma_hw_params, .hw_free = dma_hw_free, - .prepare = dma_prepare, - .trigger = dma_trigger, - .pointer = dma_pointer, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer_no_residue, .mmap = dma_mmap, }; diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 189a7a6d502..a4ab20ac0d1 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -16,6 +16,7 @@ struct s3c_dma_params { struct s3c2410_dma_client *client; /* stream identifier */ int channel; /* Channel ID */ dma_addr_t dma_addr; + int irq; int dma_size; /* Size of the DMA transfer */ unsigned ch; struct samsung_dma_ops *ops; diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b6687e30bf8..54df6db57d1 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -17,10 +17,12 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/of_irq.h> #include <linux/pm_runtime.h> #include <sound/soc.h> #include <sound/pcm_params.h> +#include <sound/dmaengine_pcm.h> #include <mach/dma.h> @@ -84,9 +86,13 @@ struct i2s_dai { #define DAI_OPENED (1 << 0) /* Dai is opened */ #define DAI_MANAGER (1 << 1) /* Dai is the manager */ unsigned mode; + /* CDCLK pin direction: 0 - input, 1 - output */ + unsigned int cdclk_out:1; /* Driver for this DAI */ struct snd_soc_dai_driver i2s_dai_drv; /* DMA parameters */ + struct snd_dmaengine_dai_dma_data snd_dma_playback; + struct snd_dmaengine_dai_dma_data snd_dma_capture; struct s3c_dma_params dma_playback; struct s3c_dma_params dma_capture; struct s3c_dma_params idma_playback; @@ -599,16 +605,19 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, break; case 2: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s->dma_playback.dma_size = 4; + i2s->snd_dma_playback.addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; else - i2s->dma_capture.dma_size = 4; + i2s->snd_dma_capture.addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; break; case 1: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - i2s->dma_playback.dma_size = 2; + i2s->snd_dma_playback.addr_width = + DMA_SLAVE_BUSWIDTH_2_BYTES; else - i2s->dma_capture.dma_size = 2; - + i2s->snd_dma_capture.addr_width = + DMA_SLAVE_BUSWIDTH_2_BYTES; break; default: dev_err(&i2s->pdev->dev, "%d channels not supported\n", @@ -658,10 +667,10 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_playback); + (void *)&i2s->snd_dma_playback); else snd_soc_dai_set_dma_data(dai, substream, - (void *)&i2s->dma_capture); + (void *)&i2s->snd_dma_capture); i2s->frmclk = params_rate(params); @@ -693,6 +702,9 @@ static int i2s_startup(struct snd_pcm_substream *substream, spin_unlock_irqrestore(&lock, flags); + if (!is_opened(other) && i2s->cdclk_out) + i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK, + 0, SND_SOC_CLOCK_OUT); return 0; } @@ -708,9 +720,13 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, i2s->mode &= ~DAI_OPENED; i2s->mode &= ~DAI_MANAGER; - if (is_opened(other)) + if (is_opened(other)) { other->mode |= DAI_MANAGER; - + } else { + u32 mod = readl(i2s->addr + I2SMOD); + i2s->cdclk_out = !(mod & MOD_CDCLKCON); + other->cdclk_out = i2s->cdclk_out; + } /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; i2s->bfs = 0; @@ -940,11 +956,9 @@ static int i2s_suspend(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - if (dai->active) { - i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); - i2s->suspend_i2scon = readl(i2s->addr + I2SCON); - i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); - } + i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); + i2s->suspend_i2scon = readl(i2s->addr + I2SCON); + i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); return 0; } @@ -953,11 +967,9 @@ static int i2s_resume(struct snd_soc_dai *dai) { struct i2s_dai *i2s = to_info(dai); - if (dai->active) { - writel(i2s->suspend_i2scon, i2s->addr + I2SCON); - writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); - writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); - } + writel(i2s->suspend_i2scon, i2s->addr + I2SCON); + writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); + writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); return 0; } @@ -998,7 +1010,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_SEC_DAI) idma_reg_addr_init(i2s->addr, - i2s->sec_dai->idma_playback.dma_addr); + i2s->sec_dai->idma_playback.dma_addr, + i2s->sec_dai->idma_playback.irq); probe_exit: /* Reset any constraint on RFS and BFS */ @@ -1028,7 +1041,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(0, i2s->addr + I2SCON); - if (!IS_ERR(i2s->op_clk)){ + if (!IS_ERR(i2s->op_clk)) { clk_disable_unprepare(i2s->op_clk); clk_put(i2s->op_clk); } @@ -1149,7 +1162,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; struct samsung_i2s *i2s_cfg = NULL; struct resource *res; - u32 regs_base, quirks = 0, idma_addr = 0; + u32 regs_base, quirks = 0, idma_addr = 0, idma_irq = 0; struct device_node *np = pdev->dev.of_node; enum samsung_dai_type samsung_dai_type; int ret = 0; @@ -1163,10 +1176,12 @@ static int samsung_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get drvdata\n"); return -EFAULT; } + snd_soc_register_component(&sec_dai->pdev->dev, &samsung_i2s_component, &sec_dai->i2s_dai_drv, 1); - asoc_dma_platform_register(&pdev->dev); + asoc_idma_platform_register(&pdev->dev); + return 0; } @@ -1218,8 +1233,15 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (of_property_read_u32(np, "samsung,idma-addr", &idma_addr)) { if (quirks & QUIRK_SEC_DAI) { - dev_err(&pdev->dev, "idma address is not"\ - "specified"); + dev_err(&pdev->dev, "idma address is not specified\n"); + return -EINVAL; + } + } + + idma_irq = irq_of_parse_and_map(np, 0); + if (idma_irq == NO_IRQ) { + if (quirks & QUIRK_SEC_DAI) { + dev_err(&pdev->dev, "idma irq is not specified\n"); return -EINVAL; } } @@ -1238,16 +1260,14 @@ static int samsung_i2s_probe(struct platform_device *pdev) } regs_base = res->start; - pri_dai->dma_playback.dma_addr = regs_base + I2STXD; - pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; - pri_dai->dma_playback.client = - (struct s3c2410_dma_client *)&pri_dai->dma_playback; - pri_dai->dma_playback.ch_name = "tx"; - pri_dai->dma_capture.client = - (struct s3c2410_dma_client *)&pri_dai->dma_capture; - pri_dai->dma_capture.ch_name = "rx"; - pri_dai->dma_playback.dma_size = 4; - pri_dai->dma_capture.dma_size = 4; + pri_dai->snd_dma_playback.addr = regs_base + I2STXD; + pri_dai->snd_dma_playback.addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; /* Default address width */ + pri_dai->snd_dma_playback.maxburst = 1; + pri_dai->snd_dma_capture.addr = regs_base + I2SRXD; + pri_dai->snd_dma_capture.addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; /* Default address width */ + pri_dai->snd_dma_capture.maxburst = 1; pri_dai->base = regs_base; pri_dai->quirks = quirks; pri_dai->op_clk = ERR_PTR(-EINVAL); @@ -1277,6 +1297,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->base = regs_base; sec_dai->quirks = quirks; sec_dai->idma_playback.dma_addr = idma_addr; + sec_dai->idma_playback.irq = idma_irq; sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; } @@ -1322,7 +1343,11 @@ static int samsung_i2s_remove(struct platform_device *pdev) i2s->pri_dai = NULL; i2s->sec_dai = NULL; - asoc_dma_platform_unregister(&pdev->dev); + if (other) + asoc_idma_platform_unregister(&pdev->dev); + else + asoc_dma_platform_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); return 0; diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index 6e5fed30aa2..8c3f912fddf 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -405,11 +405,12 @@ static int idma_new(struct snd_soc_pcm_runtime *rtd) return ret; } -void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr) +void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr, int irq) { spin_lock_init(&idma.lock); idma.regs = regs; idma.lp_tx_addr = addr; + idma_irq = irq; } EXPORT_SYMBOL_GPL(idma_reg_addr_init); @@ -419,32 +420,17 @@ static struct snd_soc_platform_driver asoc_idma_platform = { .pcm_free = idma_free, }; -static int asoc_idma_platform_probe(struct platform_device *pdev) +int asoc_idma_platform_register(struct device *dev) { - idma_irq = platform_get_irq(pdev, 0); - if (idma_irq < 0) - return idma_irq; - - return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform); + return snd_soc_register_platform(dev, &asoc_idma_platform); } +EXPORT_SYMBOL_GPL(asoc_idma_platform_register); -static int asoc_idma_platform_remove(struct platform_device *pdev) +void asoc_idma_platform_unregister(struct device *dev) { - snd_soc_unregister_platform(&pdev->dev); - return 0; + snd_soc_unregister_platform(dev); } - -static struct platform_driver asoc_idma_driver = { - .driver = { - .name = "samsung-idma", - .owner = THIS_MODULE, - }, - - .probe = asoc_idma_platform_probe, - .remove = asoc_idma_platform_remove, -}; - -module_platform_driver(asoc_idma_driver); +EXPORT_SYMBOL_GPL(asoc_idma_platform_unregister); MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); MODULE_DESCRIPTION("Samsung ASoC IDMA Driver"); diff --git a/sound/soc/samsung/idma.h b/sound/soc/samsung/idma.h index 8644946973e..b12c47f1d86 100644 --- a/sound/soc/samsung/idma.h +++ b/sound/soc/samsung/idma.h @@ -14,8 +14,10 @@ #ifndef __SND_SOC_SAMSUNG_IDMA_H_ #define __SND_SOC_SAMSUNG_IDMA_H_ -extern void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr); +extern void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr, int irq); +int asoc_idma_platform_register(struct device *dev); +void asoc_idma_platform_unregister(struct device *dev); /* dma_state */ #define LPAM_DMA_STOP 0 #define LPAM_DMA_START 1 diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 844af328835..27355a765b5 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c @@ -12,84 +12,134 @@ #include <sound/soc.h> #include <sound/pcm_params.h> #include "i2s.h" -#include "i2s-regs.h" + +struct odroidx2_drv_data { + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + + const struct snd_kcontrol_new *controls; + unsigned int num_controls; +}; /* Config I2S CDCLK output 19.2MHZ clock to Max98090 */ #define MAX98090_MCLK 19200000 -static int odroidx2_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int odroidx2_late_probe(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; int ret; ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(codec_dai->dev, - "Unable to switch to FLL1: %d\n", ret); + if (ret < 0) return ret; - } - - ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK, - 0, MOD_OPCLK_PCLK); - if (ret < 0) { - dev_err(cpu_dai->dev, - "Unable to set i2s opclk: 0x%x\n", ret); - return ret; - } /* Set the cpu DAI configuration in order to use CDCLK */ - ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, + return snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, 0, SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; +} - dev_info(codec_dai->dev, - "HiFi DAI %s params ch %d, rate %d as i2s slave\n", - ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? \ - "playback" : "capture"), - params_channels(params), - params_rate(params)); +static const struct snd_soc_dapm_widget odroidx2_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), +}; - return 0; -} +static const struct snd_kcontrol_new odroidx2_max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("DMIC"), +}; + +static const struct snd_soc_dapm_widget odroidu3_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), +}; -static struct snd_soc_ops odroidx2_ops = { - .hw_params = odroidx2_hw_params, +static const struct snd_kcontrol_new odroidu3_max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Speakers"), }; static struct snd_soc_dai_link odroidx2_dai[] = { { - .name = "MAX98090", - .stream_name = "MAX98090 PCM", - .codec_dai_name = "HiFi", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, - .ops = &odroidx2_ops, + .name = "MAX98090", + .stream_name = "MAX98090 PCM", + .codec_dai_name = "HiFi", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + }, { + .name = "MAX98090 SEC", + .stream_name = "MAX98090 PCM SEC", + .codec_dai_name = "HiFi", + .cpu_dai_name = "samsung-i2s-sec", + .platform_name = "samsung-i2s-sec", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, }, }; static struct snd_soc_card odroidx2 = { - .name = "odroidx2", - .owner = THIS_MODULE, - .dai_link = odroidx2_dai, - .num_links = ARRAY_SIZE(odroidx2_dai), + .owner = THIS_MODULE, + .dai_link = odroidx2_dai, + .num_links = ARRAY_SIZE(odroidx2_dai), + .fully_routed = true, + .late_probe = odroidx2_late_probe, +}; + +struct odroidx2_drv_data odroidx2_drvdata = { + .dapm_widgets = odroidx2_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(odroidx2_dapm_widgets), + .controls = odroidx2_max98090_controls, + .num_controls = ARRAY_SIZE(odroidx2_max98090_controls), }; +struct odroidx2_drv_data odroidu3_drvdata = { + .dapm_widgets = odroidu3_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(odroidu3_dapm_widgets), + .controls = odroidu3_max98090_controls, + .num_controls = ARRAY_SIZE(odroidu3_max98090_controls), +}; + +static const struct of_device_id odroidx2_audio_of_match[] = { + { + .compatible = "samsung,odroidx2-audio", + .data = &odroidx2_drvdata, + }, { + .compatible = "samsung,odroidu3-audio", + .data = &odroidu3_drvdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, odroidx2_audio_of_match); + static int odroidx2_audio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct snd_soc_card *card = &odroidx2; - - if (!np) - return -ENODEV; + struct odroidx2_drv_data *dd; + const struct of_device_id *of_id; + int ret; card->dev = &pdev->dev; - odroidx2_dai[0].codec_name = NULL; + of_id = of_match_node(odroidx2_audio_of_match, np); + dd = (struct odroidx2_drv_data *)of_id->data; + + card->dapm_widgets = dd->dapm_widgets; + card->num_dapm_widgets = dd->num_dapm_widgets; + card->controls = dd->controls; + card->num_controls = dd->num_controls; + + ret = snd_soc_of_parse_card_name(card, "samsung,model"); + if (ret < 0) + return ret; + + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) + return ret; + odroidx2_dai[0].codec_of_node = of_parse_phandle(np, "samsung,audio-codec", 0); if (!odroidx2_dai[0].codec_of_node) { @@ -98,18 +148,33 @@ static int odroidx2_audio_probe(struct platform_device *pdev) return -EINVAL; } - odroidx2_dai[0].cpu_name = NULL; odroidx2_dai[0].cpu_of_node = of_parse_phandle(np, "samsung,i2s-controller", 0); if (!odroidx2_dai[0].cpu_of_node) { dev_err(&pdev->dev, "Property 'samsung,i2s-controller' missing or invalid\n"); - return -EINVAL; + ret = -EINVAL; + goto err_put_cod_n; } odroidx2_dai[0].platform_of_node = odroidx2_dai[0].cpu_of_node; - return snd_soc_register_card(card); + /* Configure the secondary audio interface with the same codec dai */ + odroidx2_dai[1].codec_of_node = odroidx2_dai[0].codec_of_node; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); + goto err_put_cpu_n; + } + + return 0; + +err_put_cpu_n: + of_node_put((struct device_node *)odroidx2_dai[0].cpu_of_node); +err_put_cod_n: + of_node_put((struct device_node *)odroidx2_dai[0].codec_of_node); + return ret; } static int odroidx2_audio_remove(struct platform_device *pdev) @@ -118,25 +183,22 @@ static int odroidx2_audio_remove(struct platform_device *pdev) snd_soc_unregister_card(card); + of_node_put((struct device_node *)odroidx2_dai[0].cpu_of_node); + of_node_put((struct device_node *)odroidx2_dai[0].codec_of_node); + return 0; } -static const struct of_device_id odroidx2_audio_of_match[] = { - { .compatible = "samsung,odroidx2-audio", }, - { }, -}; -MODULE_DEVICE_TABLE(of, odroid_audio_of_match); - static struct platform_driver odroidx2_audio_driver = { .driver = { - .name = "odroidx2-audio", - .owner = THIS_MODULE, - .of_match_table = odroidx2_audio_of_match, + .name = "odroidx2-audio", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = odroidx2_audio_of_match, }, - .probe = odroidx2_audio_probe, - .remove = odroidx2_audio_remove, + .probe = odroidx2_audio_probe, + .remove = odroidx2_audio_remove, }; - module_platform_driver(odroidx2_audio_driver); MODULE_AUTHOR("zhen1.chen@samsung.com"); diff --git a/sound/soc/samsung/exynos4_wm1811.c b/sound/soc/samsung/trats2_wm1811.c index a1dbce6627c..9de4fc32119 100644 --- a/sound/soc/samsung/exynos4_wm1811.c +++ b/sound/soc/samsung/trats2_wm1811.c @@ -95,7 +95,7 @@ enum { MIC_MAX }; -enum exynos4_wm1811_gpios { +enum trats2_wm1811_gpios { GPIO_VPS_SOUND, GPIO_MIC_BIAS, GPIO_MIC_SUB_BIAS, @@ -107,7 +107,7 @@ static struct class *audio_class; static struct device *jack_dev; static struct device *caps_dev; -struct exynos_wm1811 { +struct trats2_wm1811 { struct snd_soc_jack jack; struct snd_soc_codec *codec; struct clk *codec_mclk; @@ -154,7 +154,7 @@ static int exynos_snd_micbias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct exynos_wm1811 *machine = snd_soc_card_get_drvdata(codec->card); + struct trats2_wm1811 *machine = snd_soc_card_get_drvdata(codec->card); unsigned int mic; dev_info(codec->dev, "Mic Bias: %s event is %02X", w->name, event); @@ -236,7 +236,7 @@ static int exynos_snd_vps_switch(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct exynos_wm1811 *machine = snd_soc_card_get_drvdata(codec->card); + struct trats2_wm1811 *machine = snd_soc_card_get_drvdata(codec->card); if (!gpio_is_valid(machine->gpio_vps_en)) return 0; @@ -300,7 +300,7 @@ static void codec_micd_set_rate(struct snd_soc_codec *codec) static void codec_micdet(u16 status, void *data) { - struct exynos_wm1811 *machine = data; + struct trats2_wm1811 *machine = data; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(machine->codec); int report; static int check_report; @@ -461,7 +461,7 @@ static int machine_aif1_hw_params(struct snd_pcm_substream *substream, dev_info(codec_dai->dev, "AIF1 DAI %s params ch %d, rate %d as i2s slave\n", - ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? \ + ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"), params_channels(params), params_rate(params)); @@ -548,7 +548,7 @@ static int machine_aif1_hw_params(struct snd_pcm_substream *substream, psr = 1; break; default: - printk(KERN_INFO "Not yet supported!\n"); + dev_info(codec_dai->dev, "Not yet supported!\n"); return -EINVAL; } @@ -665,7 +665,7 @@ static int machine_aif2_hw_params(struct snd_pcm_substream *substream, dev_info(codec_dai->dev, "AIF2 DAI %s params ch %d, rate %d as Clock %s\n", - ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? \ + ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"), params_channels(params), params_rate(params), @@ -684,7 +684,7 @@ static int machine_aif3_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; dev_info(codec_dai->dev, "AIF3 DAI %s params ch %d, rate %d\n", - ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? \ + ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "playback" : "capture"), params_channels(params), params_rate(params)); @@ -827,7 +827,7 @@ static DEVICE_ATTR(select_jack, S_IRUGO | S_IWUSR | S_IWGRP, static ssize_t audio_caps_cp_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct exynos_wm1811 *machine = dev_get_drvdata(dev); + struct trats2_wm1811 *machine = dev_get_drvdata(dev); if (machine->cp_wb_support == true) return sprintf(buf, "wb\n") + 1; @@ -839,7 +839,7 @@ static DEVICE_ATTR(cp_caps, S_IRUGO, audio_caps_cp_show, NULL); static ssize_t audio_caps_mic_count_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct exynos_wm1811 *machine = dev_get_drvdata(dev); + struct trats2_wm1811 *machine = dev_get_drvdata(dev); int i, cnt = 0; if (!machine) @@ -858,7 +858,7 @@ static int machine_init_paiftx(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_card *card = rtd->card; - struct exynos_wm1811 *machine = snd_soc_card_get_drvdata(card); + struct trats2_wm1811 *machine = snd_soc_card_get_drvdata(card); struct snd_soc_dai *aif1_dai = rtd->codec_dai; struct wm8994 *wm8994 = dev_get_drvdata(codec->dev->parent); int ret; @@ -1023,6 +1023,51 @@ static int machine_init_paiftx(struct snd_soc_pcm_runtime *rtd) return snd_soc_dapm_sync(&codec->dapm); } +static struct snd_soc_dai_driver voice_dai[] = { + { + .name = "voice-modem", + .playback = { + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 16000, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 16000, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, + { + .name = "voice-bluetooth", + .playback = { + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 16000, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 16000, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, +}; + +static const struct snd_soc_component_driver voice_component = { + .name = "trats2-voice", +}; + static struct snd_soc_dai_link machine_dai[] = { { /* Primary DAI i/f */ @@ -1039,7 +1084,6 @@ static struct snd_soc_dai_link machine_dai[] = { .stream_name = "Voice Tx/Rx", .cpu_dai_name = "voice-modem", .codec_dai_name = "wm8994-aif2", - .platform_name = "snd-soc-dummy", .codec_name = "wm8994-codec", .ops = &machine_aif2_ops, .ignore_suspend = 1, @@ -1048,23 +1092,16 @@ static struct snd_soc_dai_link machine_dai[] = { .stream_name = "BT Tx/Rx", .cpu_dai_name = "voice-bluetooth", .codec_dai_name = "wm8994-aif3", - .platform_name = "snd-soc-dummy", .codec_name = "wm8994-codec", .ops = &machine_aif3_ops, .ignore_suspend = 1, }, { /* Sec_Fifo DAI i/f */ - .cpu_dai_name = "samsung-i2s.4", - .codec_dai_name = "wm8994-aif1", -#ifdef CONFIG_SND_SAMSUNG_USE_IDMA .name = "Sec_FIFO TX", .stream_name = "Sec_Dai", - .platform_name = "samsung-idma", -#else - .name = "WM1811 AIF1 Playback", - .stream_name = "Pri_Dai Playback", - .platform_name = "samsung-audio", -#endif + .cpu_dai_name = "samsung-i2s-sec", + .codec_dai_name = "wm8994-aif1", + .platform_name = "samsung-i2s-sec", .codec_name = "wm8994-codec", .ops = &machine_aif1_ops, }, @@ -1072,7 +1109,7 @@ static struct snd_soc_dai_link machine_dai[] = { static int machine_card_suspend_post(struct snd_soc_card *card) { - struct exynos_wm1811 *machine = snd_soc_card_get_drvdata(card); + struct trats2_wm1811 *machine = snd_soc_card_get_drvdata(card); struct snd_soc_codec *codec = card->rtd->codec; struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; struct snd_soc_dai *aif2_dai = card->rtd[1].codec_dai; @@ -1084,8 +1121,6 @@ static int machine_card_suspend_post(struct snd_soc_card *card) to disable mclk1 from AP */ dev_info(codec->dev, "use mclk2 and disable fll"); -/* Disable this code until support for AIF2 interface is added. */ -#if 0 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2, CODEC_CLK32K, @@ -1098,7 +1133,7 @@ static int machine_card_suspend_post(struct snd_soc_card *card) if (ret < 0) dev_err(codec->dev, "Unable to stop FLL2: %d\n", ret); -#endif + ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, CODEC_CLK32K, @@ -1124,7 +1159,7 @@ static int machine_card_suspend_post(struct snd_soc_card *card) static int machine_card_resume_pre(struct snd_soc_card *card) { - struct exynos_wm1811 *machine = snd_soc_card_get_drvdata(card); + struct trats2_wm1811 *machine = snd_soc_card_get_drvdata(card); struct snd_soc_codec *codec = card->rtd->codec; struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; int reg = 0; @@ -1163,7 +1198,7 @@ static int machine_card_resume_pre(struct snd_soc_card *card) return 0; } -static int exynos4_wm1811_parse_dt(struct exynos_wm1811 *machine, +static int trats2_wm1811_parse_dt(struct trats2_wm1811 *machine, struct device *dev) { struct device_node *node = dev->of_node; @@ -1190,7 +1225,7 @@ static int exynos4_wm1811_parse_dt(struct exynos_wm1811 *machine, continue; } ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW, - mic_names[i]); + mic_names[i]); if (ret) { dev_err(dev, "%s gpio request failed\n", mic_names[i]); continue; @@ -1210,10 +1245,10 @@ static int exynos4_wm1811_parse_dt(struct exynos_wm1811 *machine, return ret; } -static int exynos4_wm1811_probe(struct platform_device *pdev) +static int trats2_wm1811_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link = &machine_dai[0]; - struct exynos_wm1811 *machine; + struct trats2_wm1811 *machine; struct snd_soc_card *card; struct clk *parent, *out_mux; int ret; @@ -1226,8 +1261,7 @@ static int exynos4_wm1811_probe(struct platform_device *pdev) return -ENOMEM; card->dai_link = machine_dai; - /* FIXME: Enable all audio interfaces */ - card->num_links = 1; /* ARRAY_SIZE(machine_dai); */ + card->num_links = ARRAY_SIZE(machine_dai); card->suspend_post = machine_card_suspend_post; card->resume_pre = machine_card_resume_pre; card->dev = &pdev->dev; @@ -1236,7 +1270,7 @@ static int exynos4_wm1811_probe(struct platform_device *pdev) if (!machine) return -ENOMEM; - ret = exynos4_wm1811_parse_dt(machine, &pdev->dev); + ret = trats2_wm1811_parse_dt(machine, &pdev->dev); if (ret < 0) return ret; @@ -1285,13 +1319,19 @@ static int exynos4_wm1811_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, machine); + /* register voice DAI */ + ret = snd_soc_register_component(&pdev->dev, &voice_component, + voice_dai, ARRAY_SIZE(voice_dai)); + if (ret) + return ret; + return snd_soc_register_card(card); } -static int exynos4_wm1811_remove(struct platform_device *pdev) +static int trats2_wm1811_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct exynos_wm1811 *machine = snd_soc_card_get_drvdata(card); + struct trats2_wm1811 *machine = snd_soc_card_get_drvdata(card); snd_soc_unregister_card(card); clk_put(machine->codec_mclk); @@ -1299,28 +1339,28 @@ static int exynos4_wm1811_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id exynos4_wm1811_of_match[] = { +static const struct of_device_id trats2_wm1811_of_match[] = { { - .compatible = "samsung,exynos4-wm1811", + .compatible = "samsung,trats2-wm1811", }, { /* sentinel */ }, }; -MODULE_DEVICE_TABLE(of, exynos4_wm1811_of_match); +MODULE_DEVICE_TABLE(of, trats2_wm1811_of_match); -static struct platform_driver exynos4_wm1811_driver = { +static struct platform_driver trats2_wm1811_driver = { .driver = { - .name = "exynos4-wm1811", - .of_match_table = exynos4_wm1811_of_match, + .name = "trats2-wm1811", + .of_match_table = trats2_wm1811_of_match, .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, }, - .probe = exynos4_wm1811_probe, - .remove = exynos4_wm1811_remove, + .probe = trats2_wm1811_probe, + .remove = trats2_wm1811_remove, }; -module_platform_driver(exynos4_wm1811_driver); +module_platform_driver(trats2_wm1811_driver); MODULE_AUTHOR("KwangHui Cho <kwanghui.cho@samsung.com>"); MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); -MODULE_DESCRIPTION("Exynos4+WM1811 machine ASoC driver"); +MODULE_DESCRIPTION("trats2 machine ASoC driver"); MODULE_LICENSE("GPL"); |