kernel/am335x-bone.patch
2013-10-11 13:26:38 -04:00

6260 lines
184 KiB
Diff

.../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 26 +-
.../devicetree/bindings/reset/gpio-reset.txt | 35 ++
arch/arm/boot/dts/Makefile | 3 +-
arch/arm/boot/dts/am335x-bone.dts | 126 +++++
arch/arm/boot/dts/am335x-boneblack.dts | 403 ++++++++++++++++
arch/arm/boot/dts/am335x-evm.dts | 7 +
arch/arm/boot/dts/am335x-evmsk.dts | 7 +
arch/arm/boot/dts/am33xx.dtsi | 60 +++
arch/arm/common/edma.c | 31 +-
arch/arm/configs/da8xx_omapl_defconfig | 3 +
arch/arm/mach-davinci/da830.c | 8 +-
arch/arm/mach-davinci/da850.c | 8 +-
arch/arm/mach-davinci/devices-da8xx.c | 42 +-
arch/arm/mach-davinci/devices-tnetv107x.c | 37 +-
arch/arm/mach-davinci/dm355.c | 52 ++-
arch/arm/mach-davinci/dm365.c | 38 +-
arch/arm/mach-davinci/dm644x.c | 52 ++-
arch/arm/mach-davinci/dm646x.c | 52 ++-
arch/arm/mach-davinci/include/mach/da8xx.h | 2 +-
arch/arm/mach-davinci/include/mach/tnetv107x.h | 2 +-
arch/arm/mach-davinci/serial.c | 19 +-
arch/arm/mach-davinci/tnetv107x.c | 8 +-
arch/arm/mach-omap2/Makefile | 3 +
arch/arm/mach-omap2/am33xx-cpsw.c | 94 ++++
arch/arm/mach-omap2/board-omap3beagle.c | 4 +-
arch/arm/mach-omap2/board-omap3evm.c | 4 +-
arch/arm/mach-omap2/board-omap3pandora.c | 2 +-
arch/arm/mach-omap2/control.h | 4 +
arch/arm/mach-omap2/omap_device.c | 232 +++++----
arch/arm/mach-omap2/omap_hwmod.c | 8 +-
arch/arm/mach-omap2/usb-host.c | 10 +-
drivers/base/platform.c | 122 +++--
drivers/dma/edma.c | 299 +++++++++---
drivers/gpu/drm/i2c/tda998x_drv.c | 518 ++++++++++++++++++---
drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 71 ++-
drivers/gpu/drm/tilcdc/tilcdc_drv.h | 5 +-
drivers/gpu/drm/tilcdc/tilcdc_panel.c | 49 +-
drivers/gpu/drm/tilcdc/tilcdc_slave.c | 65 ++-
drivers/misc/eeprom/at24.c | 23 +
drivers/mmc/host/omap_hsmmc.c | 178 +++++--
drivers/of/device.c | 3 +
drivers/of/of_i2c.c | 104 +++--
drivers/pinctrl/pinctrl-single.c | 12 +-
drivers/reset/Kconfig | 11 +
drivers/reset/Makefile | 1 +
drivers/reset/gpio-reset.c | 169 +++++++
drivers/usb/Makefile | 2 +-
drivers/usb/dwc3/dwc3-exynos.c | 8 +-
drivers/usb/dwc3/dwc3-pci.c | 8 +-
drivers/usb/gadget/Kconfig | 2 -
drivers/usb/host/Kconfig | 1 -
drivers/usb/musb/am35x.c | 2 +-
drivers/usb/musb/blackfin.c | 2 +-
drivers/usb/musb/da8xx.c | 2 +-
drivers/usb/musb/davinci.c | 2 +-
drivers/usb/musb/musb_dsps.c | 2 +-
drivers/usb/musb/tusb6010.c | 2 +-
drivers/usb/phy/Kconfig | 48 +-
drivers/usb/phy/Makefile | 4 +-
drivers/usb/phy/am35x-phy-control.h | 21 +
drivers/usb/phy/phy-am335x-control.c | 137 ++++++
drivers/usb/phy/phy-am335x.c | 99 ++++
drivers/usb/phy/phy-generic.c | 309 ++++++++++++
drivers/usb/phy/phy-generic.h | 20 +
drivers/usb/phy/phy-nop.c | 292 ------------
include/drm/i2c/tda998x.h | 23 +
include/linux/dmaengine.h | 39 ++
include/linux/i2c/eeprom.h | 59 +++
include/linux/of_i2c.h | 11 +
include/linux/platform_data/mmc-omap.h | 3 +
include/linux/platform_device.h | 4 +
include/linux/usb/nop-usb-xceiv.h | 29 --
include/linux/usb/usb_phy_gen_xceiv.h | 29 ++
sound/soc/soc-dmaengine-pcm.c | 22 +
74 files changed, 3315 insertions(+), 879 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
index ed271fc..8c8908a 100644
--- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
+++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
@@ -20,8 +20,29 @@ ti,dual-volt: boolean, supports dual voltage cards
ti,non-removable: non-removable slot (like eMMC)
ti,needs-special-reset: Requires a special softreset sequence
ti,needs-special-hs-handling: HSMMC IP needs special setting for handling High Speed
+dmas: List of DMA specifiers with the controller specific format
+as described in the generic DMA client binding. A tx and rx
+specifier is required.
+dma-names: List of DMA request names. These strings correspond
+1:1 with the DMA specifiers listed in dmas. The string naming is
+to be "rx" and "tx" for RX and TX DMA requests, respectively.
+
+Examples:
+
+[hwmod populated DMA resources]
+
+ mmc1: mmc@0x4809c000 {
+ compatible = "ti,omap4-hsmmc";
+ reg = <0x4809c000 0x400>;
+ ti,hwmods = "mmc1";
+ ti,dual-volt;
+ bus-width = <4>;
+ vmmc-supply = <&vmmc>; /* phandle to regulator node */
+ ti,non-removable;
+ };
+
+[generic DMA request binding]
-Example:
mmc1: mmc@0x4809c000 {
compatible = "ti,omap4-hsmmc";
reg = <0x4809c000 0x400>;
@@ -30,4 +51,7 @@ Example:
bus-width = <4>;
vmmc-supply = <&vmmc>; /* phandle to regulator node */
ti,non-removable;
+ dmas = <&edma 24
+ &edma 25>;
+ dma-names = "tx", "rx";
};
diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt
new file mode 100644
index 0000000..bca5348
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/gpio-reset.txt
@@ -0,0 +1,35 @@
+GPIO reset controller
+=====================
+
+A GPIO reset controller controls a single GPIO that is connected to the reset
+pin of a peripheral IC. Please also refer to reset.txt in this directory for
+common reset controller binding usage.
+
+Required properties:
+- compatible: Should be "gpio-reset"
+- reset-gpios: A gpio used as reset line. The gpio specifier for this property
+ depends on the gpio controller that provides the gpio.
+- #reset-cells: 0, see below
+
+Optional properties:
+- reset-delay-us: delay in microseconds. The gpio reset line will be asserted for
+ this duration to reset.
+- initially-in-reset: boolean. If not set, the initial state should be a
+ deasserted reset line. If this property exists, the
+ reset line should be kept in reset.
+
+example:
+
+sii902x_reset: gpio-reset {
+ compatible = "gpio-reset";
+ reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+ reset-delay-us = <10000>;
+ initially-in-reset;
+ #reset-cells = <0>;
+};
+
+/* Device with nRESET pin connected to GPIO5_0 */
+sii902x@39 {
+ /* ... */
+ resets = <&sii902x_reset>; /* active-low GPIO5_0, 10 ms delay */
+};
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 641b3c9..1b60731 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -173,7 +173,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
am335x-bone.dtb \
am3517-evm.dtb \
am3517_mt_ventoux.dtb \
- am43x-epos-evm.dtb
+ am43x-epos-evm.dtb \
+ am335x-boneblack.dtb
dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb
dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb
dtb-$(CONFIG_ARCH_U8500) += snowball.dtb \
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 444b4ed..0741775 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -110,6 +110,18 @@
0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ 0x188 0x70 /* i2c0_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
+ 0x18c 0x70 /* i2c0_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
+ >;
+ };
+ i2c2_pins: pinmux_i2c2_pins {
+ pinctrl-single,pins = <
+ 0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
+ 0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
+ >;
+ };
};
ocp {
@@ -131,7 +143,39 @@
reg = <0x24>;
};
+ baseboard_eeprom: baseboard_eeprom@50 {
+ compatible = "at,24c256";
+ reg = <0x50>;
+ };
+ };
+
+ i2c2: i2c@4819c000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "okay";
+ clock-frequency = <100000>;
+
+ cape_eeprom0: cape_eeprom0@54 {
+ compatible = "at,24c256";
+ reg = <0x54>;
+ };
+
+ cape_eeprom1: cape_eeprom1@55 {
+ compatible = "at,24c256";
+ reg = <0x55>;
+ };
+
+ cape_eeprom2: cape_eeprom2@56 {
+ compatible = "at,24c256";
+ reg = <0x56>;
+ };
+
+ cape_eeprom3: cape_eeprom3@57 {
+ compatible = "at,24c256";
+ reg = <0x57>;
+ };
};
+
};
leds {
@@ -166,6 +210,81 @@
default-state = "off";
};
};
+
+ bone_capemgr {
+ compatible = "ti,bone-capemgr";
+ status = "okay";
+
+ eeprom = <&baseboard_eeprom>;
+
+ baseboardmaps {
+ baseboard_beaglebone: board@0 {
+ board-name = "A335BONE";
+ compatible-name = "ti,beaglebone";
+ };
+
+ baseboard_beaglebone_black: board@1 {
+ board-name = "A335BNLT";
+ compatible-name = "ti,beaglebone-black";
+ };
+ };
+
+ slots {
+ slot@0 {
+ eeprom = <&cape_eeprom0>;
+ };
+
+ slot@1 {
+ eeprom = <&cape_eeprom1>;
+ };
+
+ slot@2 {
+ eeprom = <&cape_eeprom2>;
+ };
+
+ slot@3 {
+ eeprom = <&cape_eeprom3>;
+ };
+
+ /* Beaglebone black has it soldered on */
+ slot@100 {
+ ti,cape-override;
+ priority = <1>;
+ compatible = "ti,beaglebone-black";
+ board-name = "Bone-LT-eMMC-2G";
+ version = "00A0";
+ manufacturer = "Texas Instruments";
+ part-number = "BB-BONE-EMMC-2G";
+ };
+
+ /* Beaglebone black has it soldered on */
+ slot@101 {
+ ti,cape-override;
+ priority = <1>;
+ compatible = "ti,beaglebone-black";
+ board-name = "Bone-Black-HDMI";
+ version = "00A0";
+ manufacturer = "Texas Instruments";
+ part-number = "BB-BONELT-HDMI";
+ };
+
+ /* Beaglebone black has it soldered on (but no audio) */
+ slot@102 {
+ ti,cape-override;
+ priority = <2>;
+ compatible = "ti,beaglebone-black";
+ board-name = "Bone-Black-HDMIN";
+ version = "00A0";
+ manufacturer = "Texas Instruments";
+ part-number = "BB-BONELT-HDMIN";
+ };
+ };
+
+ /* mapping between board names and dtb objects */
+ capemaps {
+ /* capemaps are only needed for special cases */
+ };
+ };
};
/include/ "tps65217.dtsi"
@@ -203,6 +322,8 @@
};
ldo3_reg: regulator@5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
regulator-always-on;
};
@@ -234,3 +355,8 @@
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
};
+
+&mmc1 {
+ status = "okay";
+ vmmc-supply = <&ldo3_reg>;
+};
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
new file mode 100644
index 0000000..2ea9d5d
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+
+/ {
+ model = "TI AM335x BeagleBone";
+ compatible = "ti,am335x-bone", "ti,am33xx";
+
+ cpus {
+ cpu@0 {
+ cpu0-supply = <&dcdc2_reg>;
+
+ /*
+ * To consider voltage drop between PMIC and SoC,
+ * tolerance value is reduced to 2% from 4% and
+ * voltage value is increased as a precaution.
+ */
+ operating-points = <
+ /* kHz uV */
+ 1000000 1350000
+ 800000 1300000
+ 600000 1112000
+ 300000 969000
+ >;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>; /* 512 MB */
+ };
+
+ am33xx_pinmux: pinmux@44e10800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&clkout2_pin>;
+
+ user_leds_s0: user_leds_s0 {
+ pinctrl-single,pins = <
+ 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+ 0x58 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a6.gpio1_22 */
+ 0x5c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
+ 0x60 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a8.gpio1_24 */
+ >;
+ };
+
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ >;
+ };
+
+ uart0_pins: pinmux_uart0_pins {
+ pinctrl-single,pins = <
+ 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ >;
+ };
+
+ clkout2_pin: pinmux_clkout2_pin {
+ pinctrl-single,pins = <
+ 0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+ >;
+ };
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxerr.mii1_rxerr */
+ 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txen.mii1_txen */
+ 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxdv.mii1_rxdv */
+ 0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd3.mii1_txd3 */
+ 0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd2.mii1_txd2 */
+ 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd1.mii1_txd1 */
+ 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mii1_txd0.mii1_txd0 */
+ 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_txclk.mii1_txclk */
+ 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxclk.mii1_rxclk */
+ 0x134 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd3.mii1_rxd3 */
+ 0x138 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd2.mii1_rxd2 */
+ 0x13c (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd1.mii1_rxd1 */
+ 0x140 (PIN_INPUT_PULLUP | MUX_MODE0) /* mii1_rxd0.mii1_rxd0 */
+ >;
+ };
+
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 reset value */
+ 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ /* MDIO */
+ 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ /* MDIO reset value */
+ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ emmc_pins: pinmux_emmc_pins {
+ pinctrl-single,pins = <
+ 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+ 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+ 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+ 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+ /* eMMC_RSTn */
+ 0x50 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a4.gpio1_20 */
+ >;
+ };
+
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ 0x188 0x70 /* i2c0_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
+ 0x18c 0x70 /* i2c0_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
+ >;
+ };
+ i2c2_pins: pinmux_i2c2_pins {
+ pinctrl-single,pins = <
+ 0x178 0x73 /* uart1_ctsn.i2c2_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
+ 0x17c 0x73 /* uart1_rtsn.i2c2_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */
+ >;
+ };
+ };
+
+ ocp {
+ uart0: serial@44e09000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+
+ status = "okay";
+ };
+
+ i2c0: i2c@44e0b000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+
+ status = "okay";
+ clock-frequency = <400000>;
+
+ tps: tps@24 {
+ reg = <0x24>;
+ };
+
+ baseboard_eeprom: baseboard_eeprom@50 {
+ compatible = "at,24c256";
+ reg = <0x50>;
+ };
+ };
+
+ i2c2: i2c@4819c000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "okay";
+ clock-frequency = <100000>;
+
+ cape_eeprom0: cape_eeprom0@54 {
+ compatible = "at,24c256";
+ reg = <0x54>;
+ };
+
+ cape_eeprom1: cape_eeprom1@55 {
+ compatible = "at,24c256";
+ reg = <0x55>;
+ };
+
+ cape_eeprom2: cape_eeprom2@56 {
+ compatible = "at,24c256";
+ reg = <0x56>;
+ };
+
+ cape_eeprom3: cape_eeprom3@57 {
+ compatible = "at,24c256";
+ reg = <0x57>;
+ };
+ };
+ };
+
+ leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_leds_s0>;
+
+ compatible = "gpio-leds";
+
+ led@2 {
+ label = "beaglebone:blue:heartbeat";
+ gpios = <&gpio1 21 0>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led@3 {
+ label = "beaglebone:blue:mmc0";
+ gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+
+ led@4 {
+ label = "beaglebone:blue:usr2";
+ gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ led@5 {
+ label = "beaglebone:blue:usr3";
+ gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+
+ vmmcsd_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ bone_capemgr {
+ compatible = "ti,bone-capemgr";
+ status = "okay";
+
+ eeprom = <&baseboard_eeprom>;
+
+ baseboardmaps {
+ baseboard_beaglebone: board@0 {
+ board-name = "A335BONE";
+ compatible-name = "ti,beaglebone";
+ };
+
+ baseboard_beaglebone_black: board@1 {
+ board-name = "A335BNLT";
+ compatible-name = "ti,beaglebone-black";
+ };
+ };
+
+ slots {
+ slot@0 {
+ eeprom = <&cape_eeprom0>;
+ };
+
+ slot@1 {
+ eeprom = <&cape_eeprom1>;
+ };
+
+ slot@2 {
+ eeprom = <&cape_eeprom2>;
+ };
+
+ slot@3 {
+ eeprom = <&cape_eeprom3>;
+ };
+
+ /* Beaglebone black has it soldered on */
+ slot@100 {
+ ti,cape-override;
+ priority = <1>;
+ compatible = "ti,beaglebone-black";
+ board-name = "Bone-LT-eMMC-2G";
+ version = "00A0";
+ manufacturer = "Texas Instruments";
+ part-number = "BB-BONE-EMMC-2G";
+ };
+
+ /* Beaglebone black has it soldered on */
+ slot@101 {
+ ti,cape-override;
+ priority = <1>;
+ compatible = "ti,beaglebone-black";
+ board-name = "Bone-Black-HDMI";
+ version = "00A0";
+ manufacturer = "Texas Instruments";
+ part-number = "BB-BONELT-HDMI";
+ };
+
+ /* Beaglebone black has it soldered on (but no audio) */
+ slot@102 {
+ ti,cape-override;
+ priority = <2>;
+ compatible = "ti,beaglebone-black";
+ board-name = "Bone-Black-HDMIN";
+ version = "00A0";
+ manufacturer = "Texas Instruments";
+ part-number = "BB-BONELT-HDMIN";
+ };
+ };
+
+ /* mapping between board names and dtb objects */
+ capemaps {
+ /* capemaps are only needed for special cases */
+ };
+ };
+};
+
+/include/ "tps65217.dtsi"
+
+&tps {
+ regulators {
+ dcdc1_reg: regulator@0 {
+ regulator-always-on;
+ };
+
+ dcdc2_reg: regulator@1 {
+ /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
+ regulator-name = "vdd_mpu";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1325000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc3_reg: regulator@2 {
+ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+ regulator-name = "vdd_core";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: regulator@3 {
+ regulator-always-on;
+ };
+
+ ldo2_reg: regulator@4 {
+ regulator-always-on;
+ };
+
+ ldo3_reg: regulator@5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>; /* orig 3.3V*/
+ regulator-always-on;
+ };
+
+ ldo4_reg: regulator@6 {
+ regulator-always-on;
+ };
+ };
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <1>;
+};
+
+&mac {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+};
+
+&mmc1 {
+ status = "okay";
+ vmmc-supply = <&vmmcsd_fixed>;
+ ti,vcc-aux-disable-is-sleep;
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pins>;
+ vmmc-supply = <&ldo3_reg>;
+ bus-width = <8>;
+ ti,non-removable;
+ status = "okay";
+ ti,vcc-aux-disable-is-sleep;
+
+ reset-gpio = <&gpio1 20 GPIO_ACTIVE_HIGH>;
+};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 3aee1a4..44e69d9 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -448,6 +448,8 @@
};
vmmc_reg: regulator@12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
regulator-always-on;
};
};
@@ -488,3 +490,8 @@
ti,adc-channels = <4 5 6 7>;
};
};
+
+&mmc1 {
+ status = "okay";
+ vmmc-supply = <&vmmc_reg>;
+};
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 0c8ad17..4e355d6 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -376,6 +376,8 @@
};
vmmc_reg: regulator@12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
regulator-always-on;
};
};
@@ -402,3 +404,8 @@
phy_id = <&davinci_mdio>, <1>;
phy-mode = "rgmii-txid";
};
+
+&mmc1 {
+ status = "okay";
+ vmmc-supply = <&vmmc_reg>;
+};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 38b446b..969c81b 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -96,6 +96,18 @@
reg = <0x48200000 0x1000>;
};
+ edma: edma@49000000 {
+ compatible = "ti,edma3";
+ ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
+ reg = <0x49000000 0x10000>,
+ <0x44e10f90 0x10>;
+ interrupts = <12 13 14>;
+ #dma-cells = <1>;
+ dma-channels = <64>;
+ ti,edma-regions = <4>;
+ ti,edma-slots = <256>;
+ };
+
gpio0: gpio@44e07000 {
compatible = "ti,omap4-gpio";
ti,hwmods = "gpio1";
@@ -224,6 +236,44 @@
status = "disabled";
};
+ mmc1: mmc@48060000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc1";
+ ti,dual-volt;
+ ti,needs-special-reset;
+ ti,needs-special-hs-handling;
+ dmas = <&edma 24
+ &edma 25>;
+ dma-names = "tx", "rx";
+ interrupts = <64>;
+ interrupt-parent = <&intc>;
+ reg = <0x48060000 0x1000>;
+ status = "disabled";
+ };
+
+ mmc2: mmc@481d8000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc2";
+ ti,needs-special-reset;
+ dmas = <&edma 2
+ &edma 3>;
+ dma-names = "tx", "rx";
+ interrupts = <28>;
+ interrupt-parent = <&intc>;
+ reg = <0x481d8000 0x1000>;
+ status = "disabled";
+ };
+
+ mmc3: mmc@47810000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc3";
+ ti,needs-special-reset;
+ interrupts = <29>;
+ interrupt-parent = <&intc>;
+ reg = <0x47810000 0x1000>;
+ status = "disabled";
+ };
+
wdt2: wdt@44e35000 {
compatible = "ti,omap3-wdt";
ti,hwmods = "wd_timer2";
@@ -319,6 +369,11 @@
interrupts = <65>;
ti,spi-num-cs = <2>;
ti,hwmods = "spi0";
+ dmas = <&edma 16
+ &edma 17
+ &edma 18
+ &edma 19>;
+ dma-names = "tx0", "rx0", "tx1", "rx1";
status = "disabled";
};
@@ -330,6 +385,11 @@
interrupts = <125>;
ti,spi-num-cs = <2>;
ti,hwmods = "spi1";
+ dmas = <&edma 42
+ &edma 43
+ &edma 44
+ &edma 45>;
+ dma-names = "tx0", "rx0", "tx1", "rx1";
status = "disabled";
};
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index 39ad030..18159d7 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -560,14 +560,29 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
static int prepare_unused_channel_list(struct device *dev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- int i, ctlr;
-
- for (i = 0; i < pdev->num_resources; i++) {
- if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
- (int)pdev->resource[i].start >= 0) {
- ctlr = EDMA_CTLR(pdev->resource[i].start);
- clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
- edma_cc[ctlr]->edma_unused);
+ int i = 0, ctlr;
+ u32 dma_chan;
+ __be32 *dma_chan_p;
+ struct property *prop;
+
+ if (dev->of_node) {
+ of_property_for_each_u32(dev->of_node, "dmas", prop, \
+ dma_chan_p, dma_chan) {
+ if (i++ & 1) {
+ ctlr = EDMA_CTLR(dma_chan);
+ clear_bit(EDMA_CHAN_SLOT(dma_chan),
+ edma_cc[ctlr]->edma_unused);
+ }
+ }
+ } else {
+ for (; i < pdev->num_resources; i++) {
+ if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
+ (int)pdev->resource[i].start >= 0) {
+ ctlr = EDMA_CTLR(pdev->resource[i].start);
+ clear_bit(EDMA_CHAN_SLOT(
+ pdev->resource[i].start),
+ edma_cc[ctlr]->edma_unused);
+ }
}
}
diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index 1571bea..9b50e6c 100644
--- a/arch/arm/configs/da8xx_omapl_defconfig
+++ b/arch/arm/configs/da8xx_omapl_defconfig
@@ -106,6 +106,7 @@ CONFIG_DMADEVICES=y
CONFIG_TI_EDMA=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
CONFIG_XFS_FS=m
CONFIG_INOTIFY=y
CONFIG_AUTOFS4_FS=m
@@ -137,3 +138,5 @@ CONFIG_DEBUG_ERRORS=y
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=m
CONFIG_CRC_T10DIF=m
+CONFIG_MMC=y
+CONFIG_MMC_DAVINCI=y
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index abbaf02..a3ffd52 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -395,9 +395,9 @@ static struct clk_lookup da830_clks[] = {
CLK(NULL, "tptc0", &tptc0_clk),
CLK(NULL, "tptc1", &tptc1_clk),
CLK("da830-mmc.0", NULL, &mmcsd_clk),
- CLK(NULL, "uart0", &uart0_clk),
- CLK(NULL, "uart1", &uart1_clk),
- CLK(NULL, "uart2", &uart2_clk),
+ CLK("serial8250.0", NULL, &uart0_clk),
+ CLK("serial8250.1", NULL, &uart1_clk),
+ CLK("serial8250.2", NULL, &uart2_clk),
CLK("spi_davinci.0", NULL, &spi0_clk),
CLK("spi_davinci.1", NULL, &spi1_clk),
CLK(NULL, "ecap0", &ecap0_clk),
@@ -1199,7 +1199,7 @@ static struct davinci_soc_info davinci_soc_info_da830 = {
.gpio_base = DA8XX_GPIO_BASE,
.gpio_num = 128,
.gpio_irq = IRQ_DA8XX_GPIO0,
- .serial_dev = &da8xx_serial_device,
+ .serial_dev = da8xx_serial_device,
.emac_pdata = &da8xx_emac_pdata,
};
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a0d4f60..d4274ab 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -451,9 +451,9 @@ static struct clk_lookup da850_clks[] = {
CLK(NULL, "tpcc1", &tpcc1_clk),
CLK(NULL, "tptc2", &tptc2_clk),
CLK("pruss_uio", "pruss", &pruss_clk),
- CLK(NULL, "uart0", &uart0_clk),
- CLK(NULL, "uart1", &uart1_clk),
- CLK(NULL, "uart2", &uart2_clk),
+ CLK("serial8250.0", NULL, &uart0_clk),
+ CLK("serial8250.1", NULL, &uart1_clk),
+ CLK("serial8250.2", NULL, &uart2_clk),
CLK(NULL, "aintc", &aintc_clk),
CLK(NULL, "gpio", &gpio_clk),
CLK("i2c_davinci.2", NULL, &i2c1_clk),
@@ -1301,7 +1301,7 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
.gpio_base = DA8XX_GPIO_BASE,
.gpio_num = 144,
.gpio_irq = IRQ_DA8XX_GPIO0,
- .serial_dev = &da8xx_serial_device,
+ .serial_dev = da8xx_serial_device,
.emac_pdata = &da8xx_emac_pdata,
.sram_dma = DA8XX_SHARED_RAM_BASE,
.sram_len = SZ_128K,
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 71a46a3..280f67d 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -68,7 +68,7 @@
void __iomem *da8xx_syscfg0_base;
void __iomem *da8xx_syscfg1_base;
-static struct plat_serial8250_port da8xx_serial_pdata[] = {
+static struct plat_serial8250_port da8xx_serial0_pdata[] = {
{
.mapbase = DA8XX_UART0_BASE,
.irq = IRQ_DA8XX_UARTINT0,
@@ -78,6 +78,11 @@ static struct plat_serial8250_port da8xx_serial_pdata[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port da8xx_serial1_pdata[] = {
+ {
.mapbase = DA8XX_UART1_BASE,
.irq = IRQ_DA8XX_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -86,6 +91,11 @@ static struct plat_serial8250_port da8xx_serial_pdata[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port da8xx_serial2_pdata[] = {
+ {
.mapbase = DA8XX_UART2_BASE,
.irq = IRQ_DA8XX_UARTINT2,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -95,15 +105,33 @@ static struct plat_serial8250_port da8xx_serial_pdata[] = {
},
{
.flags = 0,
- },
+ }
};
-struct platform_device da8xx_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = da8xx_serial_pdata,
+struct platform_device da8xx_serial_device[] = {
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = da8xx_serial0_pdata,
+ }
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = da8xx_serial1_pdata,
+ }
},
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM2,
+ .dev = {
+ .platform_data = da8xx_serial2_pdata,
+ }
+ },
+ {
+ }
};
static s8 da8xx_queue_tc_mapping[][2] = {
diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
index 128cb9a..fc4a0fe 100644
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -126,7 +126,7 @@ static struct platform_device edma_device = {
.dev.platform_data = tnetv107x_edma_info,
};
-static struct plat_serial8250_port serial_data[] = {
+static struct plat_serial8250_port serial0_platform_data[] = {
{
.mapbase = TNETV107X_UART0_BASE,
.irq = IRQ_TNETV107X_UART0,
@@ -137,6 +137,11 @@ static struct plat_serial8250_port serial_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port serial1_platform_data[] = {
+ {
.mapbase = TNETV107X_UART1_BASE,
.irq = IRQ_TNETV107X_UART1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -146,6 +151,11 @@ static struct plat_serial8250_port serial_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port serial2_platform_data[] = {
+ {
.mapbase = TNETV107X_UART2_BASE,
.irq = IRQ_TNETV107X_UART2,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -156,13 +166,28 @@ static struct plat_serial8250_port serial_data[] = {
},
{
.flags = 0,
- },
+ }
};
-struct platform_device tnetv107x_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev.platform_data = serial_data,
+
+struct platform_device tnetv107x_serial_device[] = {
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev.platform_data = serial0_platform_data,
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev.platform_data = serial1_platform_data,
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM2,
+ .dev.platform_data = serial2_platform_data,
+ },
+ {
+ }
};
static struct resource mmc0_resources[] = {
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 86100d1..1701a2d 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -357,9 +357,9 @@ static struct clk_lookup dm355_clks[] = {
CLK(NULL, "clkout3", &clkout3_clk),
CLK(NULL, "arm", &arm_clk),
CLK(NULL, "mjcp", &mjcp_clk),
- CLK(NULL, "uart0", &uart0_clk),
- CLK(NULL, "uart1", &uart1_clk),
- CLK(NULL, "uart2", &uart2_clk),
+ CLK("serial8250.0", NULL, &uart0_clk),
+ CLK("serial8250.1", NULL, &uart1_clk),
+ CLK("serial8250.2", NULL, &uart2_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("davinci-mcbsp.0", NULL, &asp0_clk),
CLK("davinci-mcbsp.1", NULL, &asp1_clk),
@@ -922,7 +922,7 @@ static struct davinci_timer_info dm355_timer_info = {
.clocksource_id = T0_TOP,
};
-static struct plat_serial8250_port dm355_serial_platform_data[] = {
+static struct plat_serial8250_port dm355_serial0_platform_data[] = {
{
.mapbase = DAVINCI_UART0_BASE,
.irq = IRQ_UARTINT0,
@@ -932,6 +932,11 @@ static struct plat_serial8250_port dm355_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm355_serial1_platform_data[] = {
+ {
.mapbase = DAVINCI_UART1_BASE,
.irq = IRQ_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -940,6 +945,11 @@ static struct plat_serial8250_port dm355_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm355_serial2_platform_data[] = {
+ {
.mapbase = DM355_UART2_BASE,
.irq = IRQ_DM355_UARTINT2,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -948,16 +958,34 @@ static struct plat_serial8250_port dm355_serial_platform_data[] = {
.regshift = 2,
},
{
- .flags = 0
- },
+ .flags = 0,
+ }
};
-static struct platform_device dm355_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = dm355_serial_platform_data,
+static struct platform_device dm355_serial_device[] = {
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = dm355_serial0_platform_data,
+ }
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = dm355_serial1_platform_data,
+ }
},
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM2,
+ .dev = {
+ .platform_data = dm355_serial2_platform_data,
+ }
+ },
+ {
+ }
};
static struct davinci_soc_info davinci_soc_info_dm355 = {
@@ -981,7 +1009,7 @@ static struct davinci_soc_info davinci_soc_info_dm355 = {
.gpio_base = DAVINCI_GPIO_BASE,
.gpio_num = 104,
.gpio_irq = IRQ_DM355_GPIOBNK0,
- .serial_dev = &dm355_serial_device,
+ .serial_dev = dm355_serial_device,
.sram_dma = 0x00010000,
.sram_len = SZ_32K,
};
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index dad2802..5b3a1bc 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -455,8 +455,8 @@ static struct clk_lookup dm365_clks[] = {
CLK("vpss", "master", &vpss_master_clk),
CLK("vpss", "slave", &vpss_slave_clk),
CLK(NULL, "arm", &arm_clk),
- CLK(NULL, "uart0", &uart0_clk),
- CLK(NULL, "uart1", &uart1_clk),
+ CLK("serial8250.0", NULL, &uart0_clk),
+ CLK("serial8250.1", NULL, &uart1_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("da830-mmc.0", NULL, &mmcsd0_clk),
CLK("da830-mmc.1", NULL, &mmcsd1_clk),
@@ -1041,7 +1041,7 @@ static struct davinci_timer_info dm365_timer_info = {
#define DM365_UART1_BASE (IO_PHYS + 0x106000)
-static struct plat_serial8250_port dm365_serial_platform_data[] = {
+static struct plat_serial8250_port dm365_serial0_platform_data[] = {
{
.mapbase = DAVINCI_UART0_BASE,
.irq = IRQ_UARTINT0,
@@ -1051,6 +1051,11 @@ static struct plat_serial8250_port dm365_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm365_serial1_platform_data[] = {
+ {
.mapbase = DM365_UART1_BASE,
.irq = IRQ_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -1059,16 +1064,27 @@ static struct plat_serial8250_port dm365_serial_platform_data[] = {
.regshift = 2,
},
{
- .flags = 0
- },
+ .flags = 0,
+ }
};
-static struct platform_device dm365_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = dm365_serial_platform_data,
+static struct platform_device dm365_serial_device[] = {
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = dm365_serial0_platform_data,
+ }
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = dm365_serial1_platform_data,
+ }
},
+ {
+ }
};
static struct davinci_soc_info davinci_soc_info_dm365 = {
@@ -1093,7 +1109,7 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
.gpio_num = 104,
.gpio_irq = IRQ_DM365_GPIO0,
.gpio_unbanked = 8, /* really 16 ... skip muxed GPIOs */
- .serial_dev = &dm365_serial_device,
+ .serial_dev = dm365_serial_device,
.emac_pdata = &dm365_emac_pdata,
.sram_dma = 0x00010000,
.sram_len = SZ_32K,
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index a49d182..490eb8c 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -303,9 +303,9 @@ static struct clk_lookup dm644x_clks[] = {
CLK("vpss", "master", &vpss_master_clk),
CLK("vpss", "slave", &vpss_slave_clk),
CLK(NULL, "arm", &arm_clk),
- CLK(NULL, "uart0", &uart0_clk),
- CLK(NULL, "uart1", &uart1_clk),
- CLK(NULL, "uart2", &uart2_clk),
+ CLK("serial8250.0", NULL, &uart0_clk),
+ CLK("serial8250.1", NULL, &uart1_clk),
+ CLK("serial8250.2", NULL, &uart2_clk),
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("palm_bk3710", NULL, &ide_clk),
@@ -813,7 +813,7 @@ static struct davinci_timer_info dm644x_timer_info = {
.clocksource_id = T0_TOP,
};
-static struct plat_serial8250_port dm644x_serial_platform_data[] = {
+static struct plat_serial8250_port dm644x_serial0_platform_data[] = {
{
.mapbase = DAVINCI_UART0_BASE,
.irq = IRQ_UARTINT0,
@@ -823,6 +823,11 @@ static struct plat_serial8250_port dm644x_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm644x_serial1_platform_data[] = {
+ {
.mapbase = DAVINCI_UART1_BASE,
.irq = IRQ_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -831,6 +836,11 @@ static struct plat_serial8250_port dm644x_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm644x_serial2_platform_data[] = {
+ {
.mapbase = DAVINCI_UART2_BASE,
.irq = IRQ_UARTINT2,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -839,16 +849,34 @@ static struct plat_serial8250_port dm644x_serial_platform_data[] = {
.regshift = 2,
},
{
- .flags = 0
- },
+ .flags = 0,
+ }
};
-static struct platform_device dm644x_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = dm644x_serial_platform_data,
+static struct platform_device dm644x_serial_device[] = {
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = dm644x_serial0_platform_data,
+ }
},
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = dm644x_serial1_platform_data,
+ }
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM2,
+ .dev = {
+ .platform_data = dm644x_serial2_platform_data,
+ }
+ },
+ {
+ }
};
static struct davinci_soc_info davinci_soc_info_dm644x = {
@@ -872,7 +900,7 @@ static struct davinci_soc_info davinci_soc_info_dm644x = {
.gpio_base = DAVINCI_GPIO_BASE,
.gpio_num = 71,
.gpio_irq = IRQ_GPIOBNK0,
- .serial_dev = &dm644x_serial_device,
+ .serial_dev = dm644x_serial_device,
.emac_pdata = &dm644x_emac_pdata,
.sram_dma = 0x00008000,
.sram_len = SZ_16K,
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index d1259e8..23609b1 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -342,9 +342,9 @@ static struct clk_lookup dm646x_clks[] = {
CLK(NULL, "edma_tc1", &edma_tc1_clk),
CLK(NULL, "edma_tc2", &edma_tc2_clk),
CLK(NULL, "edma_tc3", &edma_tc3_clk),
- CLK(NULL, "uart0", &uart0_clk),
- CLK(NULL, "uart1", &uart1_clk),
- CLK(NULL, "uart2", &uart2_clk),
+ CLK("serial8250.0", NULL, &uart0_clk),
+ CLK("serial8250.1", NULL, &uart1_clk),
+ CLK("serial8250.2", NULL, &uart2_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK(NULL, "gpio", &gpio_clk),
CLK("davinci-mcasp.0", NULL, &mcasp0_clk),
@@ -790,7 +790,7 @@ static struct davinci_timer_info dm646x_timer_info = {
.clocksource_id = T0_TOP,
};
-static struct plat_serial8250_port dm646x_serial_platform_data[] = {
+static struct plat_serial8250_port dm646x_serial0_platform_data[] = {
{
.mapbase = DAVINCI_UART0_BASE,
.irq = IRQ_UARTINT0,
@@ -800,6 +800,11 @@ static struct plat_serial8250_port dm646x_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm646x_serial1_platform_data[] = {
+ {
.mapbase = DAVINCI_UART1_BASE,
.irq = IRQ_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -808,6 +813,11 @@ static struct plat_serial8250_port dm646x_serial_platform_data[] = {
.regshift = 2,
},
{
+ .flags = 0,
+ }
+};
+static struct plat_serial8250_port dm646x_serial2_platform_data[] = {
+ {
.mapbase = DAVINCI_UART2_BASE,
.irq = IRQ_DM646X_UARTINT2,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
@@ -816,16 +826,34 @@ static struct plat_serial8250_port dm646x_serial_platform_data[] = {
.regshift = 2,
},
{
- .flags = 0
- },
+ .flags = 0,
+ }
};
-static struct platform_device dm646x_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = dm646x_serial_platform_data,
+static struct platform_device dm646x_serial_device[] = {
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = dm646x_serial0_platform_data,
+ }
+ },
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = dm646x_serial1_platform_data,
+ }
},
+ {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM2,
+ .dev = {
+ .platform_data = dm646x_serial2_platform_data,
+ }
+ },
+ {
+ }
};
static struct davinci_soc_info davinci_soc_info_dm646x = {
@@ -849,7 +877,7 @@ static struct davinci_soc_info davinci_soc_info_dm646x = {
.gpio_base = DAVINCI_GPIO_BASE,
.gpio_num = 43, /* Only 33 usable */
.gpio_irq = IRQ_DM646X_GPIOBNK0,
- .serial_dev = &dm646x_serial_device,
+ .serial_dev = dm646x_serial_device,
.emac_pdata = &dm646x_emac_pdata,
.sram_dma = 0x10010000,
.sram_len = SZ_32K,
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 7b41a5e..aae5307 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -111,7 +111,7 @@ void da8xx_restart(enum reboot_mode mode, const char *cmd);
void da8xx_rproc_reserve_cma(void);
int da8xx_register_rproc(void);
-extern struct platform_device da8xx_serial_device;
+extern struct platform_device da8xx_serial_device[];
extern struct emac_platform_data da8xx_emac_pdata;
extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata;
extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata;
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index 16314c6..beb7c0e 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -50,7 +50,7 @@ struct tnetv107x_device_info {
};
extern struct platform_device tnetv107x_wdt_device;
-extern struct platform_device tnetv107x_serial_device;
+extern struct platform_device tnetv107x_serial_device[];
extern void tnetv107x_init(void);
extern void tnetv107x_devices_init(struct tnetv107x_device_info *);
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index f262581..57e6150 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -76,7 +76,7 @@ int __init davinci_serial_setup_clk(unsigned instance, unsigned int *rate)
char name[16];
struct clk *clk;
struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct device *dev = &soc_info->serial_dev->dev;
+ struct device *dev = &soc_info->serial_dev[instance].dev;
sprintf(name, "uart%d", instance);
clk = clk_get(dev, name);
@@ -96,19 +96,25 @@ int __init davinci_serial_setup_clk(unsigned instance, unsigned int *rate)
int __init davinci_serial_init(struct davinci_uart_config *info)
{
- int i, ret;
+ int i, ret = 0;
struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct device *dev = &soc_info->serial_dev->dev;
- struct plat_serial8250_port *p = dev->platform_data;
+ struct device *dev;
+ struct plat_serial8250_port *p;
/*
* Make sure the serial ports are muxed on at this point.
* You have to mux them off in device drivers later on if not needed.
*/
- for (i = 0; p->flags; i++, p++) {
+ for (i = 0; soc_info->serial_dev[i].dev.platform_data != NULL; i++) {
+ dev = &soc_info->serial_dev[i].dev;
+ p = dev->platform_data;
if (!(info->enabled_uarts & (1 << i)))
continue;
+ ret = platform_device_register(&soc_info->serial_dev[i]);
+ if (ret)
+ continue;
+
ret = davinci_serial_setup_clk(i, &p->uartclk);
if (ret)
continue;
@@ -125,6 +131,5 @@ int __init davinci_serial_init(struct davinci_uart_config *info)
if (p->membase && p->type != PORT_AR7)
davinci_serial_reset(p);
}
-
- return platform_device_register(soc_info->serial_dev);
+ return ret;
}
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index 4545667..f4d7fbb 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -264,7 +264,7 @@ static struct clk_lookup clks[] = {
CLK(NULL, "clk_chipcfg", &clk_chipcfg),
CLK("tnetv107x-ts.0", NULL, &clk_tsc),
CLK(NULL, "clk_rom", &clk_rom),
- CLK(NULL, "uart2", &clk_uart2),
+ CLK("serial8250.2", NULL, &clk_uart2),
CLK(NULL, "clk_pktsec", &clk_pktsec),
CLK("tnetv107x-rng.0", NULL, &clk_rng),
CLK("tnetv107x-pka.0", NULL, &clk_pka),
@@ -274,8 +274,8 @@ static struct clk_lookup clks[] = {
CLK(NULL, "clk_gpio", &clk_gpio),
CLK(NULL, "clk_mdio", &clk_mdio),
CLK("dm6441-mmc.0", NULL, &clk_sdio0),
- CLK(NULL, "uart0", &clk_uart0),
- CLK(NULL, "uart1", &clk_uart1),
+ CLK("serial8250.0", NULL, &clk_uart0),
+ CLK("serial8250.1", NULL, &clk_uart1),
CLK(NULL, "timer0", &clk_timer0),
CLK(NULL, "timer1", &clk_timer1),
CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm),
@@ -757,7 +757,7 @@ static struct davinci_soc_info tnetv107x_soc_info = {
.gpio_type = GPIO_TYPE_TNETV107X,
.gpio_num = TNETV107X_N_GPIO,
.timer_info = &timer_info,
- .serial_dev = &tnetv107x_serial_device,
+ .serial_dev = tnetv107x_serial_device,
};
void __init tnetv107x_init(void)
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index d4f6715..7c0ef46 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -295,4 +295,7 @@ endif
emac-$(CONFIG_TI_DAVINCI_EMAC) := am35xx-emac.o
obj-y += $(emac-m) $(emac-y)
+cpsw-$(CONFIG_TI_CPSW) := am33xx-cpsw.o
+obj-y += $(cpsw-m) $(cpsw-y)
+
obj-y += common-board-devices.o twl-common.o dss-common.o
diff --git a/arch/arm/mach-omap2/am33xx-cpsw.c b/arch/arm/mach-omap2/am33xx-cpsw.c
new file mode 100644
index 0000000..5a674d9
--- /dev/null
+++ b/arch/arm/mach-omap2/am33xx-cpsw.c
@@ -0,0 +1,94 @@
+/*
+ * am335x specific cpsw dt fixups
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/etherdevice.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+
+#include "soc.h"
+#include "control.h"
+
+/**
+ * am33xx_dt_cpsw_set_mac_from_efuse - Add mac-address property using
+ * ethernet hwaddr from efuse
+ * @np: Pointer to the cpsw slave to set mac address of
+ * @idx: Mac address index to use from efuse
+ */
+static void am33xx_dt_cpsw_set_mac_from_efuse(struct device_node *np, int idx)
+{
+ struct property *prop;
+ u32 lo, hi;
+ u8 *mac;
+
+ switch (idx) {
+ case 0:
+ lo = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID0_LOW);
+ hi = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID0_HIGH);
+ break;
+
+ case 1:
+ lo = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID1_LOW);
+ hi = omap_ctrl_readl(AM33XX_CONTROL_MAC_ID1_HIGH);
+ break;
+
+ default:
+ pr_err("cpsw.%d: too many slaves found\n", idx);
+ return;
+ }
+
+ prop = kzalloc(sizeof(*prop) + ETH_ALEN, GFP_KERNEL);
+ if (!prop)
+ return;
+
+ prop->value = prop + 1;
+ prop->length = ETH_ALEN;
+ prop->name = kstrdup("mac-address", GFP_KERNEL);
+ if (!prop->name) {
+ kfree(prop);
+ return;
+ }
+
+ mac = prop->value;
+
+ mac[0] = hi;
+ mac[1] = hi >> 8;
+ mac[2] = hi >> 16;
+ mac[3] = hi >> 24;
+ mac[4] = lo;
+ mac[5] = lo >> 8;
+
+ of_update_property(np, prop);
+
+ pr_info("cpsw.%d: No hwaddr in dt. Using %pM from efuse\n", idx, mac);
+}
+
+static int __init am33xx_dt_cpsw_mac_fixup(void)
+{
+ struct device_node *np, *slave;
+ int idx = 0;
+
+ if (!soc_is_am33xx())
+ return -ENODEV;
+
+ for_each_compatible_node(np, NULL, "ti,cpsw")
+ for_each_node_by_name(slave, "slave") {
+ if (!of_get_mac_address(slave))
+ am33xx_dt_cpsw_set_mac_from_efuse(slave, idx);
+ idx++;
+ }
+
+ return 0;
+}
+arch_initcall(am33xx_dt_cpsw_mac_fixup);
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 04c1165..1c6ae5f 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -33,7 +33,7 @@
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -279,7 +279,7 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = {
static struct gpio_led gpio_leds[];
/* PHY's VCC regulator might be added later, so flag that we need it */
-static struct nop_usb_xceiv_platform_data hsusb2_phy_data = {
+static struct usb_phy_gen_xceiv_platform_data hsusb2_phy_data = {
.needs_vcc = true,
};
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 8c02626..52bdddd 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -33,7 +33,7 @@
#include <linux/i2c/twl.h>
#include <linux/usb/otg.h>
#include <linux/usb/musb.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/smsc911x.h>
#include <linux/wl12xx.h>
@@ -468,7 +468,7 @@ struct wl12xx_platform_data omap3evm_wlan_data __initdata = {
static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = {
REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"), /* OMAP ISP */
REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"), /* OMAP ISP */
- REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */
+ REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */
REGULATOR_SUPPLY("vaux2", NULL),
};
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index b1547a0..d2b455e 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -352,7 +352,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = {
};
static struct regulator_consumer_supply pandora_usb_phy_supply[] = {
- REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */
+ REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */
};
/* ads7846 on SPI and 2 nub controllers on I2C */
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index f7d7c2e..5d684b7 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -352,6 +352,10 @@
/* AM33XX CONTROL_STATUS register */
#define AM33XX_CONTROL_STATUS 0x040
#define AM33XX_CONTROL_SEC_CLK_CTRL 0x1bc
+#define AM33XX_CONTROL_MAC_ID0_LOW 0x630
+#define AM33XX_CONTROL_MAC_ID0_HIGH 0x634
+#define AM33XX_CONTROL_MAC_ID1_LOW 0x638
+#define AM33XX_CONTROL_MAC_ID1_HIGH 0x63c
/* AM33XX CONTROL_STATUS bitfields (partial) */
#define AM33XX_CONTROL_STATUS_SYSBOOT1_SHIFT 22
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index f99f68e..dc7a56d 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -330,30 +330,156 @@ static int omap_device_fill_resources(struct omap_device *od,
}
/**
- * _od_fill_dma_resources - fill in array of struct resource with dma resources
+ * omap_device_fixup_resources - Fix platform device resources
* @od: struct omap_device *
- * @res: pointer to an array of struct resource to be filled in
- *
- * Populate one or more empty struct resource pointed to by @res with
- * the dma resource data for this omap_device @od. Used by
- * omap_device_alloc() after calling omap_device_count_resources().
- *
- * Ideally this function would not be needed at all. If we have
- * mechanism to get dma resources from DT.
*
- * Returns 0.
+ * Fixup the platform device resources so that the resources
+ * from the hwmods are included for.
*/
-static int _od_fill_dma_resources(struct omap_device *od,
- struct resource *res)
+static int omap_device_fixup_resources(struct omap_device *od)
{
- int i, r;
+ struct platform_device *pdev = od->pdev;
+ int i, j, ret, res_count;
+ struct resource *res, *r, *rnew, *rn;
+ unsigned long type;
- for (i = 0; i < od->hwmods_cnt; i++) {
- r = omap_hwmod_fill_dma_resources(od->hwmods[i], res);
- res += r;
+ /*
+ * DT Boot:
+ * OF framework will construct the resource structure (currently
+ * does for MEM & IRQ resource) and we should respect/use these
+ * resources, killing hwmod dependency.
+ * If pdev->num_resources > 0, we assume that MEM & IRQ resources
+ * have been allocated by OF layer already (through DTB).
+ *
+ * Non-DT Boot:
+ * Here, pdev->num_resources = 0, and we should get all the
+ * resources from hwmod.
+ *
+ * TODO: Once DMA resource is available from OF layer, we should
+ * kill filling any resources from hwmod.
+ */
+
+ /* count number of resources hwmod provides */
+ res_count = omap_device_count_resources(od, IORESOURCE_IRQ |
+ IORESOURCE_DMA | IORESOURCE_MEM);
+
+ /* if no resources from hwmod, we're done already */
+ if (res_count == 0)
+ return 0;
+
+ /* Allocate resources memory to account for all hwmod resources */
+ res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
+ if (!res) {
+ ret = -ENOMEM;
+ goto fail_no_res;
+ }
+
+ /* fill all the resources */
+ ret = omap_device_fill_resources(od, res);
+ if (ret != 0)
+ goto fail_no_fill;
+
+ /*
+ * If pdev->num_resources > 0, then assume that,
+ * MEM and IRQ resources will only come from DT and only
+ * fill DMA resource from hwmod layer.
+ */
+ if (pdev->num_resources > 0) {
+
+ dev_dbg(&pdev->dev, "%s(): resources allocated %d hwmod #%d\n",
+ __func__, pdev->num_resources, res_count);
+
+ /* find number of resources needing to be inserted */
+ for (i = 0, j = 0, r = res; i < res_count; i++, r++) {
+ type = resource_type(r);
+ if (type == IORESOURCE_DMA)
+ j++;
+ }
+
+ /* no need to insert anything, just return */
+ if (j == 0) {
+ kfree(res);
+ return 0;
+ }
+
+ /* we need to insert j additional resources */
+ rnew = kzalloc(sizeof(*rnew) *
+ (pdev->num_resources + j), GFP_KERNEL);
+ if (rnew == NULL)
+ goto fail_no_rnew;
+
+ /*
+ * Unlink any resources from any lists.
+ * This is important since the copying destroys any
+ * linkage
+ */
+ for (i = 0, r = pdev->resource;
+ i < pdev->num_resources; i++, r++) {
+
+ if (!r->parent)
+ continue;
+
+ dev_dbg(&pdev->dev,
+ "Releasing resource %p\n", r);
+ release_resource(r);
+ r->parent = NULL;
+ r->sibling = NULL;
+ r->child = NULL;
+ }
+
+ memcpy(rnew, pdev->resource,
+ sizeof(*rnew) * pdev->num_resources);
+
+ /* now append the resources from the hwmods */
+ rn = rnew + pdev->num_resources;
+ for (i = 0, r = res; i < res_count; i++, r++) {
+
+ type = resource_type(r);
+ if (type != IORESOURCE_DMA)
+ continue;
+
+ /* append the hwmod resource */
+ memcpy(rn, r, sizeof(*r));
+
+ /* make sure these are zeroed out */
+ rn->parent = NULL;
+ rn->child = NULL;
+ rn->sibling = NULL;
+
+ rn++;
+ }
+ kfree(res); /* we don't need res anymore */
+
+ /* this is our new resource table */
+ res = rnew;
+ res_count = j + pdev->num_resources;
+
+ } else {
+ dev_dbg(&pdev->dev, "%s(): using resources from hwmod %d\n",
+ __func__, res_count);
}
+ ret = platform_device_add_resources(pdev, res, res_count);
+ kfree(res);
+
+ /* failed to add the resources? */
+ if (ret != 0)
+ return ret;
+
+ /* finally link all the resources again */
+ ret = platform_device_link_resources(pdev);
+ if (ret != 0)
+ return ret;
+
return 0;
+
+fail_no_rnew:
+ /* nothing */
+fail_no_fill:
+ kfree(res);
+
+fail_no_res:
+ return ret;
}
/**
@@ -373,9 +499,8 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
{
int ret = -ENOMEM;
struct omap_device *od;
- struct resource *res = NULL;
- int i, res_count;
struct omap_hwmod **hwmods;
+ int i;
od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
if (!od) {
@@ -385,79 +510,18 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
od->hwmods_cnt = oh_cnt;
hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
- if (!hwmods)
+ if (!hwmods) {
+ ret = -ENOMEM;
goto oda_exit2;
+ }
od->hwmods = hwmods;
od->pdev = pdev;
- /*
- * Non-DT Boot:
- * Here, pdev->num_resources = 0, and we should get all the
- * resources from hwmod.
- *
- * DT Boot:
- * OF framework will construct the resource structure (currently
- * does for MEM & IRQ resource) and we should respect/use these
- * resources, killing hwmod dependency.
- * If pdev->num_resources > 0, we assume that MEM & IRQ resources
- * have been allocated by OF layer already (through DTB).
- * As preparation for the future we examine the OF provided resources
- * to see if we have DMA resources provided already. In this case
- * there is no need to update the resources for the device, we use the
- * OF provided ones.
- *
- * TODO: Once DMA resource is available from OF layer, we should
- * kill filling any resources from hwmod.
- */
- if (!pdev->num_resources) {
- /* Count all resources for the device */
- res_count = omap_device_count_resources(od, IORESOURCE_IRQ |
- IORESOURCE_DMA |
- IORESOURCE_MEM);
- } else {
- /* Take a look if we already have DMA resource via DT */
- for (i = 0; i < pdev->num_resources; i++) {
- struct resource *r = &pdev->resource[i];
-
- /* We have it, no need to touch the resources */
- if (r->flags == IORESOURCE_DMA)
- goto have_everything;
- }
- /* Count only DMA resources for the device */
- res_count = omap_device_count_resources(od, IORESOURCE_DMA);
- /* The device has no DMA resource, no need for update */
- if (!res_count)
- goto have_everything;
-
- res_count += pdev->num_resources;
- }
-
- /* Allocate resources memory to account for new resources */
- res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
- if (!res)
- goto oda_exit3;
-
- if (!pdev->num_resources) {
- dev_dbg(&pdev->dev, "%s: using %d resources from hwmod\n",
- __func__, res_count);
- omap_device_fill_resources(od, res);
- } else {
- dev_dbg(&pdev->dev,
- "%s: appending %d DMA resources from hwmod\n",
- __func__, res_count - pdev->num_resources);
- memcpy(res, pdev->resource,
- sizeof(struct resource) * pdev->num_resources);
- _od_fill_dma_resources(od, &res[pdev->num_resources]);
- }
-
- ret = platform_device_add_resources(pdev, res, res_count);
- kfree(res);
-
- if (ret)
+ ret = omap_device_fixup_resources(od);
+ if (ret != 0)
goto oda_exit3;
-have_everything:
pdev->archdata.od = od;
for (i = 0; i < oh_cnt; i++) {
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 7f4db12..b887451 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -784,7 +784,9 @@ static int _init_interface_clks(struct omap_hwmod *oh)
if (IS_ERR(c)) {
pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n",
oh->name, os->clk);
- ret = -EINVAL;
+ if (ret == 0)
+ ret = -EINVAL;
+ continue;
}
os->_clk = c;
/*
@@ -820,7 +822,9 @@ static int _init_opt_clks(struct omap_hwmod *oh)
if (IS_ERR(c)) {
pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n",
oh->name, oc->clk);
- ret = -EINVAL;
+ if (ret == 0)
+ ret = -EINVAL;
+ continue;
}
oc->_clk = c;
/*
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 2eb19d4..e83a6a4 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -28,7 +28,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/usb/phy.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include "soc.h"
#include "omap_device.h"
@@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = {
/* .init_data filled later */
};
-static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */
+static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */
static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */
/**
@@ -460,9 +460,9 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys)
pdevinfo.name = nop_name;
pdevinfo.id = phy->port;
pdevinfo.data = phy->platform_data;
- pdevinfo.size_data = sizeof(struct nop_usb_xceiv_platform_data);
-
- scnprintf(phy_id, MAX_STR, "nop_usb_xceiv.%d",
+ pdevinfo.size_data =
+ sizeof(struct usb_phy_gen_xceiv_platform_data);
+ scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d",
phy->port);
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) {
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3c3197a..65c774c 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -267,6 +267,80 @@ int platform_device_add_data(struct platform_device *pdev, const void *data,
}
EXPORT_SYMBOL_GPL(platform_device_add_data);
+static struct resource *platform_device_parent_resource(
+ struct platform_device *pdev, struct resource *r)
+{
+ unsigned long type;
+
+ if (r->parent)
+ return r->parent;
+
+ type = resource_type(r);
+ switch (type) {
+ case IORESOURCE_MEM:
+ return &iomem_resource;
+ case IORESOURCE_IO:
+ return &ioport_resource;
+ /* TODO: What about the other resources? */
+ default:
+ break;
+ }
+ pr_debug("%s: no parent for resource %p type 0x%lx\n",
+ dev_name(&pdev->dev), r, resource_type(r));
+ return NULL;
+}
+
+int platform_device_unlink_resources(struct platform_device *pdev)
+{
+ struct resource *r;
+ int i;
+
+ for (i = pdev->num_resources - 1; i >= 0; i--) {
+ r = &pdev->resource[i];
+ if (r->parent == NULL)
+ continue;
+ release_resource(r);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(platform_device_unlink_resources);
+
+int platform_device_link_resources(struct platform_device *pdev)
+{
+ int i;
+ struct resource *p, *r;
+
+ for (i = 0; i < pdev->num_resources; i++) {
+ r = &pdev->resource[i];
+
+ if (r->name == NULL)
+ r->name = dev_name(&pdev->dev);
+
+ /* already linked */
+ if (r->parent != NULL)
+ continue;
+
+ p = platform_device_parent_resource(pdev, r);
+ if (p && insert_resource(p, r)) {
+ pr_err("%s: failed to claim resource %d\n",
+ dev_name(&pdev->dev), i);
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ while (--i >= 0) {
+ r = &pdev->resource[i];
+ if (r->parent == NULL)
+ continue;
+ release_resource(r);
+ }
+ return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(platform_device_link_resources);
+
/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
@@ -276,7 +350,7 @@ EXPORT_SYMBOL_GPL(platform_device_add_data);
*/
int platform_device_add(struct platform_device *pdev)
{
- int i, ret;
+ int ret;
if (!pdev)
return -EINVAL;
@@ -308,26 +382,10 @@ int platform_device_add(struct platform_device *pdev)
break;
}
- for (i = 0; i < pdev->num_resources; i++) {
- struct resource *p, *r = &pdev->resource[i];
-
- if (r->name == NULL)
- r->name = dev_name(&pdev->dev);
-
- p = r->parent;
- if (!p) {
- if (resource_type(r) == IORESOURCE_MEM)
- p = &iomem_resource;
- else if (resource_type(r) == IORESOURCE_IO)
- p = &ioport_resource;
- }
-
- if (p && insert_resource(p, r)) {
- dev_err(&pdev->dev, "failed to claim resource %d\n", i);
- ret = -EBUSY;
- goto failed;
- }
- }
+ /* make sure the resources are linked properly */
+ ret = platform_device_link_resources(pdev);
+ if (ret != 0)
+ goto failed_res;
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
@@ -336,20 +394,14 @@ int platform_device_add(struct platform_device *pdev)
if (ret == 0)
return ret;
- failed:
+ platform_device_unlink_resources(pdev);
+
+ failed_res:
if (pdev->id_auto) {
ida_simple_remove(&platform_devid_ida, pdev->id);
pdev->id = PLATFORM_DEVID_AUTO;
}
- while (--i >= 0) {
- struct resource *r = &pdev->resource[i];
- unsigned long type = resource_type(r);
-
- if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
- release_resource(r);
- }
-
err_out:
return ret;
}
@@ -365,8 +417,6 @@ EXPORT_SYMBOL_GPL(platform_device_add);
*/
void platform_device_del(struct platform_device *pdev)
{
- int i;
-
if (pdev) {
device_del(&pdev->dev);
@@ -375,13 +425,7 @@ void platform_device_del(struct platform_device *pdev)
pdev->id = PLATFORM_DEVID_AUTO;
}
- for (i = 0; i < pdev->num_resources; i++) {
- struct resource *r = &pdev->resource[i];
- unsigned long type = resource_type(r);
-
- if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
- release_resource(r);
- }
+ platform_device_unlink_resources(pdev);
}
}
EXPORT_SYMBOL_GPL(platform_device_del);
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 5f3e532..cec9a12 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -70,6 +70,7 @@ struct edma_chan {
bool alloced;
int slot[EDMA_MAX_SLOTS];
struct dma_slave_config cfg;
+ struct dma_slave_sg_limits sg_limits;
};
struct edma_cc {
@@ -210,6 +211,198 @@ static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
return ret;
}
+/*
+ * A clean implementation of a PaRAM set configuration abstraction
+ * @chan: Channel who's PaRAM set we're configuring
+ * @src_addr: Source address of the DMA
+ * @dst_addr: Destination address of the DMA
+ * @burst: In units of dev_width, how much to send
+ * @dev_width: How much is the dev_width
+ * @dma_length: Total length of the DMA transfer
+ * @direction: Direction of the transfer
+ */
+static int edma_config_pset(struct dma_chan *chan, struct edmacc_param *pset,
+ dma_addr_t src_addr, dma_addr_t dst_addr, u32 burst,
+ enum dma_slave_buswidth dev_width, unsigned int dma_length,
+ enum dma_transfer_direction direction)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ struct device *dev = chan->device->dev;
+ int acnt, bcnt, ccnt, cidx;
+ int src_bidx, dst_bidx, src_cidx, dst_cidx;
+ int absync;
+
+ acnt = dev_width;
+ /*
+ * If the maxburst is equal to the fifo width, use
+ * A-synced transfers. This allows for large contiguous
+ * buffer transfers using only one PaRAM set.
+ */
+ if (burst == 1) {
+ absync = false;
+ /*
+ * For the A-sync case, bcnt and ccnt are the remainder
+ * and quotient respectively of the division of:
+ * (dma_length / acnt) by (SZ_64K -1). This is so
+ * that in case bcnt over flows, we have ccnt to use.
+ * Note: In A-sync tranfer only, bcntrld is used, but it
+ * only applies for sg_dma_len(sg) >= SZ_64K.
+ * In this case, the best way adopted is- bccnt for the
+ * first frame will be the remainder below. Then for
+ * every successive frame, bcnt will be SZ_64K-1. This
+ * is assured as bcntrld = 0xffff in end of function.
+ */
+ ccnt = dma_length / acnt / (SZ_64K - 1);
+ bcnt = dma_length / acnt - ccnt * (SZ_64K - 1);
+ /*
+ * If bcnt is non-zero, we have a remainder and hence an
+ * extra frame to transfer, so increment ccnt.
+ */
+ if (bcnt)
+ ccnt++;
+ else
+ bcnt = SZ_64K - 1;
+ cidx = acnt;
+ /*
+ * If maxburst is greater than the fifo address_width,
+ * use AB-synced transfers where A count is the fifo
+ * address_width and B count is the maxburst. In this
+ * case, we are limited to transfers of C count frames
+ * of (address_width * maxburst) where C count is limited
+ * to SZ_64K-1. This places an upper bound on the length
+ * of an SG segment that can be handled.
+ */
+ } else {
+ absync = true;
+ bcnt = burst;
+ ccnt = dma_length / (acnt * bcnt);
+ if (ccnt > (SZ_64K - 1)) {
+ dev_err(dev, "Exceeded max SG segment size\n");
+ return -EINVAL;
+ }
+ cidx = acnt * bcnt;
+ }
+
+ if (direction == DMA_MEM_TO_DEV) {
+ src_bidx = acnt;
+ src_cidx = cidx;
+ dst_bidx = 0;
+ dst_cidx = 0;
+ } else if (direction == DMA_DEV_TO_MEM) {
+ src_bidx = 0;
+ src_cidx = 0;
+ dst_bidx = acnt;
+ dst_cidx = cidx;
+ } else {
+ dev_err(dev, "%s: direction not implemented yet\n", __func__);
+ return -EINVAL;
+ }
+
+ pset->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
+ /* Configure A or AB synchronized transfers */
+ if (absync)
+ pset->opt |= SYNCDIM;
+
+ pset->src = src_addr;
+ pset->dst = dst_addr;
+
+ pset->src_dst_bidx = (dst_bidx << 16) | src_bidx;
+ pset->src_dst_cidx = (dst_cidx << 16) | src_cidx;
+
+ pset->a_b_cnt = bcnt << 16 | acnt;
+ pset->ccnt = ccnt;
+ /*
+ * Only time when (bcntrld) auto reload is required is for
+ * A-sync case, and in this case, a requirement of reload value
+ * of SZ_64K-1 only is assured. 'link' is initially set to NULL
+ * and then later will be populated by edma_execute.
+ */
+ pset->link_bcntrld = 0xffffffff;
+ return absync;
+}
+
+static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction, unsigned long flags,
+ void *context)
+{
+ struct edma_chan *echan = to_edma_chan(chan);
+ struct device *dev = chan->device->dev;
+ struct edma_desc *edesc;
+ dma_addr_t src_addr, dst_addr;
+ enum dma_slave_buswidth dev_width;
+ u32 burst;
+ int i, ret, nr_periods;
+
+ if (unlikely(!echan || !buf_len || !period_len))
+ return NULL;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ src_addr = echan->cfg.src_addr;
+ dst_addr = buf_addr;
+ dev_width = echan->cfg.src_addr_width;
+ burst = echan->cfg.src_maxburst;
+ } else if (direction == DMA_MEM_TO_DEV) {
+ src_addr = buf_addr;
+ dst_addr = echan->cfg.dst_addr;
+ dev_width = echan->cfg.dst_addr_width;
+ burst = echan->cfg.dst_maxburst;
+ } else {
+ dev_err(dev, "%s: bad direction?\n", __func__);
+ return NULL;
+ }
+
+ if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
+ dev_err(dev, "Undefined slave buswidth\n");
+ return NULL;
+ }
+
+ if(unlikely(period_len % buf_len)) {
+ dev_err(dev, "Period should be multiple of Buf length\n");
+ return NULL;
+ }
+
+ nr_periods = period_len / buf_len;
+
+ edesc = kzalloc(sizeof(*edesc) + nr_periods *
+ sizeof(edesc->pset[0]), GFP_ATOMIC);
+ if (!edesc) {
+ dev_dbg(dev, "Failed to allocate a descriptor\n");
+ return NULL;
+ }
+
+ edesc->pset_nr = nr_periods;
+
+ for(i = 0; i < nr_periods; i++) {
+ /* Allocate a PaRAM slot, if needed */
+ if (echan->slot[i] < 0) {
+ echan->slot[i] =
+ edma_alloc_slot(EDMA_CTLR(echan->ch_num),
+ EDMA_SLOT_ANY);
+ if (echan->slot[i] < 0) {
+ dev_err(dev, "Failed to allocate slot\n");
+ return NULL;
+ }
+ }
+
+ if (direction == DMA_DEV_TO_MEM)
+ dst_addr += period_len;
+ else
+ src_addr += period_len;
+
+ ret = edma_config_pset(chan, &edesc->pset[i], src_addr, dst_addr,
+ burst, dev_width, period_len, direction);
+ if(ret < 0)
+ return NULL;
+
+ edesc->absync = ret;
+ if (i == nr_periods - 1)
+ edesc->pset[i].opt |= TCINTEN;
+ }
+ /* TODO tx_flags (last parameter) needs to be investigated...\n" */
+ return vchan_tx_prep(&echan->vchan, &edesc->vdesc, 0);
+}
+
static struct dma_async_tx_descriptor *edma_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@@ -218,23 +411,21 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
struct edma_chan *echan = to_edma_chan(chan);
struct device *dev = chan->device->dev;
struct edma_desc *edesc;
- dma_addr_t dev_addr;
+ dma_addr_t src_addr = 0, dst_addr = 0;
enum dma_slave_buswidth dev_width;
u32 burst;
struct scatterlist *sg;
- int i;
- int acnt, bcnt, ccnt, src, dst, cidx;
- int src_bidx, dst_bidx, src_cidx, dst_cidx;
+ int i, ret;
if (unlikely(!echan || !sgl || !sg_len))
return NULL;
if (direction == DMA_DEV_TO_MEM) {
- dev_addr = echan->cfg.src_addr;
+ src_addr = echan->cfg.src_addr;
dev_width = echan->cfg.src_addr_width;
burst = echan->cfg.src_maxburst;
} else if (direction == DMA_MEM_TO_DEV) {
- dev_addr = echan->cfg.dst_addr;
+ dst_addr = echan->cfg.dst_addr;
dev_width = echan->cfg.dst_addr_width;
burst = echan->cfg.dst_maxburst;
} else {
@@ -262,7 +453,14 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
edesc->pset_nr = sg_len;
+ /* Configure PaRAM sets for each SG */
for_each_sg(sgl, sg, sg_len, i) {
+ /* Get address for each SG */
+ if (direction == DMA_DEV_TO_MEM)
+ dst_addr = sg_dma_address(sg);
+ else
+ src_addr = sg_dma_address(sg);
+
/* Allocate a PaRAM slot, if needed */
if (echan->slot[i] < 0) {
echan->slot[i] =
@@ -274,76 +472,16 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
}
}
- acnt = dev_width;
-
- /*
- * If the maxburst is equal to the fifo width, use
- * A-synced transfers. This allows for large contiguous
- * buffer transfers using only one PaRAM set.
- */
- if (burst == 1) {
- edesc->absync = false;
- ccnt = sg_dma_len(sg) / acnt / (SZ_64K - 1);
- bcnt = sg_dma_len(sg) / acnt - ccnt * (SZ_64K - 1);
- if (bcnt)
- ccnt++;
- else
- bcnt = SZ_64K - 1;
- cidx = acnt;
- /*
- * If maxburst is greater than the fifo address_width,
- * use AB-synced transfers where A count is the fifo
- * address_width and B count is the maxburst. In this
- * case, we are limited to transfers of C count frames
- * of (address_width * maxburst) where C count is limited
- * to SZ_64K-1. This places an upper bound on the length
- * of an SG segment that can be handled.
- */
- } else {
- edesc->absync = true;
- bcnt = burst;
- ccnt = sg_dma_len(sg) / (acnt * bcnt);
- if (ccnt > (SZ_64K - 1)) {
- dev_err(dev, "Exceeded max SG segment size\n");
- return NULL;
- }
- cidx = acnt * bcnt;
- }
+ ret = edma_config_pset(chan, &edesc->pset[i], src_addr, dst_addr,
+ burst, dev_width, sg_dma_len(sg), direction);
+ if(ret < 0)
+ return NULL;
- if (direction == DMA_MEM_TO_DEV) {
- src = sg_dma_address(sg);
- dst = dev_addr;
- src_bidx = acnt;
- src_cidx = cidx;
- dst_bidx = 0;
- dst_cidx = 0;
- } else {
- src = dev_addr;
- dst = sg_dma_address(sg);
- src_bidx = 0;
- src_cidx = 0;
- dst_bidx = acnt;
- dst_cidx = cidx;
- }
+ edesc->absync = ret;
- edesc->pset[i].opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
- /* Configure A or AB synchronized transfers */
- if (edesc->absync)
- edesc->pset[i].opt |= SYNCDIM;
/* If this is the last set, enable completion interrupt flag */
if (i == sg_len - 1)
edesc->pset[i].opt |= TCINTEN;
-
- edesc->pset[i].src = src;
- edesc->pset[i].dst = dst;
-
- edesc->pset[i].src_dst_bidx = (dst_bidx << 16) | src_bidx;
- edesc->pset[i].src_dst_cidx = (dst_cidx << 16) | src_cidx;
-
- edesc->pset[i].a_b_cnt = bcnt << 16 | acnt;
- edesc->pset[i].ccnt = ccnt;
- edesc->pset[i].link_bcntrld = 0xffffffff;
-
}
return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
@@ -368,6 +506,8 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
edesc = echan->edesc;
if (edesc) {
edma_execute(echan);
+ /* Note: that desc->callback must be setup by EDMA users so that
+ the virt-dma layer calls their callback on vchan_cookie_complete() */
vchan_cookie_complete(&edesc->vdesc);
}
@@ -462,6 +602,20 @@ static void edma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&echan->vchan.lock, flags);
}
+static struct dma_slave_sg_limits
+*edma_get_slave_sg_limits(struct dma_chan *chan,
+ enum dma_slave_buswidth addr_width,
+ u32 maxburst)
+{
+ struct edma_chan *echan;
+
+ echan = to_edma_chan(chan);
+ echan->sg_limits.max_seg_len =
+ (SZ_64K - 1) * addr_width * maxburst;
+
+ return &echan->sg_limits;
+}
+
static size_t edma_desc_size(struct edma_desc *edesc)
{
int i;
@@ -521,6 +675,7 @@ static void __init edma_chan_init(struct edma_cc *ecc,
echan->ch_num = EDMA_CTLR_CHAN(ecc->ctlr, i);
echan->ecc = ecc;
echan->vchan.desc_free = edma_desc_free;
+ echan->sg_limits.max_seg_nr = MAX_NR_SG;
vchan_init(&echan->vchan, dma);
@@ -534,9 +689,11 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
struct device *dev)
{
dma->device_prep_slave_sg = edma_prep_slave_sg;
+ dma->device_prep_dma_cyclic = edma_prep_dma_cyclic;
dma->device_alloc_chan_resources = edma_alloc_chan_resources;
dma->device_free_chan_resources = edma_free_chan_resources;
dma->device_issue_pending = edma_issue_pending;
+ dma->device_slave_sg_limits = edma_get_slave_sg_limits;
dma->device_tx_status = edma_tx_status;
dma->device_control = edma_control;
dma->dev = dev;
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index e68b58a..967d0c3 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -23,7 +23,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_edid.h>
-
+#include <drm/i2c/tda998x.h>
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
@@ -32,6 +32,11 @@ struct tda998x_priv {
uint16_t rev;
uint8_t current_page;
int dpms;
+ bool is_hdmi_sink;
+ u8 vip_cntrl_0;
+ u8 vip_cntrl_1;
+ u8 vip_cntrl_2;
+ struct tda998x_encoder_params params;
};
#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv)
@@ -68,10 +73,13 @@ struct tda998x_priv {
# define I2C_MASTER_DIS_MM (1 << 0)
# define I2C_MASTER_DIS_FILT (1 << 1)
# define I2C_MASTER_APP_STRT_LAT (1 << 2)
+#define REG_FEAT_POWERDOWN REG(0x00, 0x0e) /* read/write */
+# define FEAT_POWERDOWN_SPDIF (1 << 3)
#define REG_INT_FLAGS_0 REG(0x00, 0x0f) /* read/write */
#define REG_INT_FLAGS_1 REG(0x00, 0x10) /* read/write */
#define REG_INT_FLAGS_2 REG(0x00, 0x11) /* read/write */
# define INT_FLAGS_2_EDID_BLK_RD (1 << 1)
+#define REG_ENA_ACLK REG(0x00, 0x16) /* read/write */
#define REG_ENA_VP_0 REG(0x00, 0x18) /* read/write */
#define REG_ENA_VP_1 REG(0x00, 0x19) /* read/write */
#define REG_ENA_VP_2 REG(0x00, 0x1a) /* read/write */
@@ -110,6 +118,8 @@ struct tda998x_priv {
#define REG_VIP_CNTRL_5 REG(0x00, 0x25) /* write */
# define VIP_CNTRL_5_CKCASE (1 << 0)
# define VIP_CNTRL_5_SP_CNT(x) (((x) & 3) << 1)
+#define REG_MUX_AP REG(0x00, 0x26) /* read/write */
+#define REG_MUX_VP_VIP_OUT REG(0x00, 0x27) /* read/write */
#define REG_MAT_CONTRL REG(0x00, 0x80) /* write */
# define MAT_CONTRL_MAT_SC(x) (((x) & 3) << 0)
# define MAT_CONTRL_MAT_BP (1 << 2)
@@ -130,8 +140,12 @@ struct tda998x_priv {
#define REG_VS_LINE_END_1_LSB REG(0x00, 0xae) /* write */
#define REG_VS_PIX_END_1_MSB REG(0x00, 0xaf) /* write */
#define REG_VS_PIX_END_1_LSB REG(0x00, 0xb0) /* write */
+#define REG_VS_LINE_STRT_2_MSB REG(0x00, 0xb1) /* write */
+#define REG_VS_LINE_STRT_2_LSB REG(0x00, 0xb2) /* write */
#define REG_VS_PIX_STRT_2_MSB REG(0x00, 0xb3) /* write */
#define REG_VS_PIX_STRT_2_LSB REG(0x00, 0xb4) /* write */
+#define REG_VS_LINE_END_2_MSB REG(0x00, 0xb5) /* write */
+#define REG_VS_LINE_END_2_LSB REG(0x00, 0xb6) /* write */
#define REG_VS_PIX_END_2_MSB REG(0x00, 0xb7) /* write */
#define REG_VS_PIX_END_2_LSB REG(0x00, 0xb8) /* write */
#define REG_HS_PIX_START_MSB REG(0x00, 0xb9) /* write */
@@ -142,21 +156,29 @@ struct tda998x_priv {
#define REG_VWIN_START_1_LSB REG(0x00, 0xbe) /* write */
#define REG_VWIN_END_1_MSB REG(0x00, 0xbf) /* write */
#define REG_VWIN_END_1_LSB REG(0x00, 0xc0) /* write */
+#define REG_VWIN_START_2_MSB REG(0x00, 0xc1) /* write */
+#define REG_VWIN_START_2_LSB REG(0x00, 0xc2) /* write */
+#define REG_VWIN_END_2_MSB REG(0x00, 0xc3) /* write */
+#define REG_VWIN_END_2_LSB REG(0x00, 0xc4) /* write */
#define REG_DE_START_MSB REG(0x00, 0xc5) /* write */
#define REG_DE_START_LSB REG(0x00, 0xc6) /* write */
#define REG_DE_STOP_MSB REG(0x00, 0xc7) /* write */
#define REG_DE_STOP_LSB REG(0x00, 0xc8) /* write */
#define REG_TBG_CNTRL_0 REG(0x00, 0xca) /* write */
+# define TBG_CNTRL_0_TOP_TGL (1 << 0)
+# define TBG_CNTRL_0_TOP_SEL (1 << 1)
+# define TBG_CNTRL_0_DE_EXT (1 << 2)
+# define TBG_CNTRL_0_TOP_EXT (1 << 3)
# define TBG_CNTRL_0_FRAME_DIS (1 << 5)
# define TBG_CNTRL_0_SYNC_MTHD (1 << 6)
# define TBG_CNTRL_0_SYNC_ONCE (1 << 7)
#define REG_TBG_CNTRL_1 REG(0x00, 0xcb) /* write */
-# define TBG_CNTRL_1_VH_TGL_0 (1 << 0)
-# define TBG_CNTRL_1_VH_TGL_1 (1 << 1)
-# define TBG_CNTRL_1_VH_TGL_2 (1 << 2)
-# define TBG_CNTRL_1_VHX_EXT_DE (1 << 3)
-# define TBG_CNTRL_1_VHX_EXT_HS (1 << 4)
-# define TBG_CNTRL_1_VHX_EXT_VS (1 << 5)
+# define TBG_CNTRL_1_H_TGL (1 << 0)
+# define TBG_CNTRL_1_V_TGL (1 << 1)
+# define TBG_CNTRL_1_TGL_EN (1 << 2)
+# define TBG_CNTRL_1_X_EXT (1 << 3)
+# define TBG_CNTRL_1_H_EXT (1 << 4)
+# define TBG_CNTRL_1_V_EXT (1 << 5)
# define TBG_CNTRL_1_DWIN_DIS (1 << 6)
#define REG_ENABLE_SPACE REG(0x00, 0xd6) /* write */
#define REG_HVF_CNTRL_0 REG(0x00, 0xe4) /* write */
@@ -171,6 +193,12 @@ struct tda998x_priv {
# define HVF_CNTRL_1_PAD(x) (((x) & 3) << 4)
# define HVF_CNTRL_1_SEMI_PLANAR (1 << 6)
#define REG_RPT_CNTRL REG(0x00, 0xf0) /* write */
+#define REG_I2S_FORMAT REG(0x00, 0xfc) /* read/write */
+# define I2S_FORMAT(x) (((x) & 3) << 0)
+#define REG_AIP_CLKSEL REG(0x00, 0xfd) /* write */
+# define AIP_CLKSEL_FS(x) (((x) & 3) << 0)
+# define AIP_CLKSEL_CLK_POL(x) (((x) & 1) << 2)
+# define AIP_CLKSEL_AIP(x) (((x) & 7) << 3)
/* Page 02h: PLL settings */
@@ -212,6 +240,11 @@ struct tda998x_priv {
/* Page 10h: information frames and packets */
+#define REG_IF1_HB0 REG(0x10, 0x20) /* read/write */
+#define REG_IF2_HB0 REG(0x10, 0x40) /* read/write */
+#define REG_IF3_HB0 REG(0x10, 0x60) /* read/write */
+#define REG_IF4_HB0 REG(0x10, 0x80) /* read/write */
+#define REG_IF5_HB0 REG(0x10, 0xa0) /* read/write */
/* Page 11h: audio settings and content info packets */
@@ -221,14 +254,39 @@ struct tda998x_priv {
# define AIP_CNTRL_0_LAYOUT (1 << 2)
# define AIP_CNTRL_0_ACR_MAN (1 << 5)
# define AIP_CNTRL_0_RST_CTS (1 << 6)
+#define REG_CA_I2S REG(0x11, 0x01) /* read/write */
+# define CA_I2S_CA_I2S(x) (((x) & 31) << 0)
+# define CA_I2S_HBR_CHSTAT (1 << 6)
+#define REG_LATENCY_RD REG(0x11, 0x04) /* read/write */
+#define REG_ACR_CTS_0 REG(0x11, 0x05) /* read/write */
+#define REG_ACR_CTS_1 REG(0x11, 0x06) /* read/write */
+#define REG_ACR_CTS_2 REG(0x11, 0x07) /* read/write */
+#define REG_ACR_N_0 REG(0x11, 0x08) /* read/write */
+#define REG_ACR_N_1 REG(0x11, 0x09) /* read/write */
+#define REG_ACR_N_2 REG(0x11, 0x0a) /* read/write */
+#define REG_CTS_N REG(0x11, 0x0c) /* read/write */
+# define CTS_N_K(x) (((x) & 7) << 0)
+# define CTS_N_M(x) (((x) & 3) << 4)
#define REG_ENC_CNTRL REG(0x11, 0x0d) /* read/write */
# define ENC_CNTRL_RST_ENC (1 << 0)
# define ENC_CNTRL_RST_SEL (1 << 1)
# define ENC_CNTRL_CTL_CODE(x) (((x) & 3) << 2)
+#define REG_DIP_FLAGS REG(0x11, 0x0e) /* read/write */
+# define DIP_FLAGS_ACR (1 << 0)
+# define DIP_FLAGS_GC (1 << 1)
+#define REG_DIP_IF_FLAGS REG(0x11, 0x0f) /* read/write */
+# define DIP_IF_FLAGS_IF1 (1 << 1)
+# define DIP_IF_FLAGS_IF2 (1 << 2)
+# define DIP_IF_FLAGS_IF3 (1 << 3)
+# define DIP_IF_FLAGS_IF4 (1 << 4)
+# define DIP_IF_FLAGS_IF5 (1 << 5)
+#define REG_CH_STAT_B(x) REG(0x11, 0x14 + (x)) /* read/write */
/* Page 12h: HDCP and OTP */
#define REG_TX3 REG(0x12, 0x9a) /* read/write */
+#define REG_TX4 REG(0x12, 0x9b) /* read/write */
+# define TX4_PD_RAM (1 << 1)
#define REG_TX33 REG(0x12, 0xb8) /* read/write */
# define TX33_HDMI (1 << 1)
@@ -338,6 +396,23 @@ fail:
return ret;
}
+static void
+reg_write_range(struct drm_encoder *encoder, uint16_t reg, uint8_t *p, int cnt)
+{
+ struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+ uint8_t buf[cnt+1];
+ int ret;
+
+ buf[0] = REG2ADDR(reg);
+ memcpy(&buf[1], p, cnt);
+
+ set_page(encoder, reg);
+
+ ret = i2c_master_send(client, buf, cnt + 1);
+ if (ret < 0)
+ dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
+}
+
static uint8_t
reg_read(struct drm_encoder *encoder, uint16_t reg)
{
@@ -415,11 +490,192 @@ tda998x_reset(struct drm_encoder *encoder)
reg_write(encoder, REG_PLL_SCG2, 0x10);
}
+static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes)
+{
+ uint8_t sum = 0;
+
+ while (bytes--)
+ sum += *buf++;
+ return (255 - sum) + 1;
+}
+
+#define HB(x) (x)
+#define PB(x) (HB(2) + 1 + (x))
+
+static void
+tda998x_write_if(struct drm_encoder *encoder, uint8_t bit, uint16_t addr,
+ uint8_t *buf, size_t size)
+{
+ buf[PB(0)] = tda998x_cksum(buf, size);
+
+ reg_clear(encoder, REG_DIP_IF_FLAGS, bit);
+ reg_write_range(encoder, addr, buf, size);
+ reg_set(encoder, REG_DIP_IF_FLAGS, bit);
+}
+
+static void
+tda998x_write_aif(struct drm_encoder *encoder, struct tda998x_encoder_params *p)
+{
+ uint8_t buf[PB(5) + 1];
+
+ buf[HB(0)] = 0x84;
+ buf[HB(1)] = 0x01;
+ buf[HB(2)] = 10;
+ buf[PB(0)] = 0;
+ buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */
+ buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */
+ buf[PB(4)] = p->audio_frame[4];
+ buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
+
+ tda998x_write_if(encoder, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
+ sizeof(buf));
+}
+
+static void
+tda998x_write_avi(struct drm_encoder *encoder, struct drm_display_mode *mode)
+{
+ uint8_t buf[PB(13) + 1];
+
+ memset(buf, 0, sizeof(buf));
+ buf[HB(0)] = 0x82;
+ buf[HB(1)] = 0x02;
+ buf[HB(2)] = 13;
+ buf[PB(4)] = drm_match_cea_mode(mode);
+
+ tda998x_write_if(encoder, DIP_IF_FLAGS_IF2, REG_IF2_HB0, buf,
+ sizeof(buf));
+}
+
+static void tda998x_audio_mute(struct drm_encoder *encoder, bool on)
+{
+ if (on) {
+ reg_set(encoder, REG_SOFTRESET, SOFTRESET_AUDIO);
+ reg_clear(encoder, REG_SOFTRESET, SOFTRESET_AUDIO);
+ reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
+ } else {
+ reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
+ }
+}
+
+static void
+tda998x_configure_audio(struct drm_encoder *encoder, struct tda998x_encoder_params *p)
+{
+ uint8_t buf[6], clksel_aip, clksel_fs, ca_i2s, cts_n;
+ uint32_t n;
+
+ /* SetAudioPortConfig */
+ reg_write(encoder, REG_ENA_AP, p->audio_cfg);
+ /* SetAudioClockPortConfig */
+ reg_write(encoder, REG_ENA_ACLK, p->audio_clk_cfg);
+
+ /*
+ * layout = channelAllocation ? 1 : 0;
+ * AudioInSetConfig(format, i2sFormat, channelAllocation,
+ * HDMITX_CHAN_NO_CHANGE, HDMITX_CLKPOLDSD_NO_CHANGE,
+ * HDMITX_SWAPDSD_NO_CHANGE, layout, HDMITX_LATENCY_CURRENT,
+ * dstRate)
+ */
+ switch (p->audio_format) {
+ case AFMT_SPDIF:
+ reg_write(encoder, REG_MUX_AP, 0x40);
+ clksel_aip = AIP_CLKSEL_AIP(0);
+ /* FS64SPDIF */
+ clksel_fs = AIP_CLKSEL_FS(2);
+ cts_n = CTS_N_M(3) | CTS_N_K(3);
+ ca_i2s = 0;
+ break;
+
+ case AFMT_I2S:
+ reg_write(encoder, REG_MUX_AP, 0x64);
+ clksel_aip = AIP_CLKSEL_AIP(1);
+ /* ACLK */
+ clksel_fs = AIP_CLKSEL_FS(0);
+ cts_n = CTS_N_M(3) | CTS_N_K(3);
+ ca_i2s = CA_I2S_CA_I2S(0 /* channel allocation */);
+ break;
+ }
+
+ reg_write(encoder, REG_AIP_CLKSEL, clksel_aip);
+// reg_write(encoder, REG_CA_I2S, ca_i2s);
+// reg_write(encoder, REG_I2S_FORMAT, I2S_FORMAT(0 /* i2s format */));
+ reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT);
+ /* latency? */
+
+ /* get video format */
+
+ /*
+ * ctsRef = HDMITX_CTSREF_FS64SPDIF, uCtsX = HDMITX_CTSX_64
+ * AudioInSetCts(ctsRef, rate, VidFmt, vOutFreq,
+ * HDMITX_CTS_AUTO, uCtsX, HDMITX_CTSK_USE_CTSX,
+ * HDMITX_CTSMTS_USE_CTSX, dstRate)
+ */
+ /* Auto CTS */
+ reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_ACR_MAN);
+ reg_write(encoder, REG_CTS_N, cts_n);
+ reg_write(encoder, REG_AUDIO_DIV, 3);
+
+ /*
+ * This is the approximate value of N, which happens to be
+ * the recommended values for non-coherent clocks.
+ */
+ n = 128 * p->audio_sample_rate / 1000;
+
+ /* Write the CTS and N values */
+ buf[0] = 0x44;
+ buf[1] = 0x42;
+ buf[2] = 0x01;
+ buf[3] = n;
+ buf[4] = n >> 8;
+ buf[5] = n >> 16;
+ reg_write_range(encoder, REG_ACR_CTS_0, buf, 6);
+
+ /* Set CTS clock reference */
+ reg_write(encoder, REG_AIP_CLKSEL, clksel_aip | clksel_fs);
+
+ /* Reset CTS generator */
+ reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
+ reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
+
+ /* Write the channel status */
+ buf[0] = 0x04;
+ buf[1] = 0x00;
+ buf[2] = 0x00;
+ buf[3] = 0xf1;
+ reg_write_range(encoder, REG_CH_STAT_B(0), buf, 4);
+
+ tda998x_audio_mute(encoder, true);
+ mdelay(20);
+ tda998x_audio_mute(encoder, false);
+
+ /* Write the audio information packet */
+ tda998x_write_aif(encoder, p);
+}
+
/* DRM encoder functions */
static void
tda998x_encoder_set_config(struct drm_encoder *encoder, void *params)
{
+ struct tda998x_priv *priv = to_tda998x_priv(encoder);
+ struct tda998x_encoder_params *p = params;
+
+ priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) |
+ (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) |
+ VIP_CNTRL_0_SWAP_B(p->swap_b) |
+ (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0);
+ priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) |
+ (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) |
+ VIP_CNTRL_1_SWAP_D(p->swap_d) |
+ (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0);
+ priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) |
+ (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) |
+ VIP_CNTRL_2_SWAP_F(p->swap_f) |
+ (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
+
+ priv->params = *p;
+
+ if (p->audio_cfg)
+ tda998x_configure_audio(encoder, p);
}
static void
@@ -436,22 +692,22 @@ tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
+ /* Write the default value MUX register */
+ reg_write(encoder, REG_MUX_VP_VIP_OUT, 0x24);
/* enable audio and video ports */
- reg_write(encoder, REG_ENA_AP, 0xff);
+// reg_write(encoder, REG_ENA_AP, priv->ena_ap);
+// reg_write(encoder, REG_ENA_ACLK, priv->ena_aclk);
reg_write(encoder, REG_ENA_VP_0, 0xff);
reg_write(encoder, REG_ENA_VP_1, 0xff);
reg_write(encoder, REG_ENA_VP_2, 0xff);
/* set muxing after enabling ports: */
- reg_write(encoder, REG_VIP_CNTRL_0,
- VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3));
- reg_write(encoder, REG_VIP_CNTRL_1,
- VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1));
- reg_write(encoder, REG_VIP_CNTRL_2,
- VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5));
+ reg_write(encoder, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
+ reg_write(encoder, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
+ reg_write(encoder, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
break;
case DRM_MODE_DPMS_OFF:
/* disable audio and video ports */
- reg_write(encoder, REG_ENA_AP, 0x00);
+// reg_write(encoder, REG_ENA_AP, 0x00);
reg_write(encoder, REG_ENA_VP_0, 0x00);
reg_write(encoder, REG_ENA_VP_1, 0x00);
reg_write(encoder, REG_ENA_VP_2, 0x00);
@@ -494,42 +750,77 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct tda998x_priv *priv = to_tda998x_priv(encoder);
- uint16_t hs_start, hs_end, line_start, line_end;
- uint16_t vwin_start, vwin_end, de_start, de_end;
- uint16_t ref_pix, ref_line, pix_start2;
+ uint16_t ref_pix, ref_line, n_pix, n_line;
+ uint16_t hs_pix_s, hs_pix_e;
+ uint16_t vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
+ uint16_t vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e;
+ uint16_t vwin1_line_s, vwin1_line_e;
+ uint16_t vwin2_line_s, vwin2_line_e;
+ uint16_t de_pix_s, de_pix_e;
uint8_t reg, div, rep;
- hs_start = mode->hsync_start - mode->hdisplay;
- hs_end = mode->hsync_end - mode->hdisplay;
- line_start = 1;
- line_end = 1 + mode->vsync_end - mode->vsync_start;
- vwin_start = mode->vtotal - mode->vsync_start;
- vwin_end = vwin_start + mode->vdisplay;
- de_start = mode->htotal - mode->hdisplay;
- de_end = mode->htotal;
-
- pix_start2 = 0;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- pix_start2 = (mode->htotal / 2) + hs_start;
-
- /* TODO how is this value calculated? It is 2 for all common
- * formats in the tables in out of tree nxp driver (assuming
- * I've properly deciphered their byzantine table system)
+ /*
+ * Internally TDA998x is using ITU-R BT.656 style sync but
+ * we get VESA style sync. TDA998x is using a reference pixel
+ * relative to ITU to sync to the input frame and for output
+ * sync generation.
+ *
+ * Now there is some issues to take care of:
+ * - HDMI data islands require sync-before-active
+ * - TDA998x register values must be > 0 to be enabled
+ * - REFLINE needs an additional offset of +1
+ * - REFPIX needs an addtional offset of +1 for UYUV and +3 for RGB
+ *
+ * So we add +1 to all horizontal and vertical register values,
+ * plus an additional +3 for REFPIX as we are using RGB input only.
*/
- ref_line = 2;
+ n_pix = mode->htotal;
+ n_line = mode->vtotal;
- /* this might changes for other color formats from the CRTC: */
- ref_pix = 3 + hs_start;
+ ref_pix = 3 + mode->hsync_start - mode->hdisplay;
- div = 148500 / mode->clock;
+ /*
+ * handle issue on TILCDC where it is outputing
+ * non-VESA compliant sync signals the workaround
+ * forces us to invert the HSYNC, so need to adjust display to
+ * the left by hskew pixels, provided by the tilcdc driver
+ */
+ if(adjusted_mode && adjusted_mode->flags & DRM_MODE_FLAG_HSKEW)
+ ref_pix += adjusted_mode->hskew;
+
+ de_pix_s = mode->htotal - mode->hdisplay;
+ de_pix_e = de_pix_s + mode->hdisplay;
+ hs_pix_s = mode->hsync_start - mode->hdisplay;
+ hs_pix_e = hs_pix_s + mode->hsync_end - mode->hsync_start;
+
+ if ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0) {
+ ref_line = 1 + mode->vsync_start - mode->vdisplay;
+ vwin1_line_s = mode->vtotal - mode->vdisplay - 1;
+ vwin1_line_e = vwin1_line_s + mode->vdisplay;
+ vs1_pix_s = vs1_pix_e = hs_pix_s;
+ vs1_line_s = mode->vsync_start - mode->vdisplay;
+ vs1_line_e = vs1_line_s +
+ mode->vsync_end - mode->vsync_start;
+ vwin2_line_s = vwin2_line_e = 0;
+ vs2_pix_s = vs2_pix_e = 0;
+ vs2_line_s = vs2_line_e = 0;
+ } else {
+ ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2;
+ vwin1_line_s = (mode->vtotal - mode->vdisplay)/2;
+ vwin1_line_e = vwin1_line_s + mode->vdisplay/2;
+ vs1_pix_s = vs1_pix_e = hs_pix_s;
+ vs1_line_s = (mode->vsync_start - mode->vdisplay)/2;
+ vs1_line_e = vs1_line_s +
+ (mode->vsync_end - mode->vsync_start)/2;
+ vwin2_line_s = vwin1_line_s + mode->vtotal/2;
+ vwin2_line_e = vwin2_line_s + mode->vdisplay/2;
+ vs2_pix_s = vs2_pix_e = hs_pix_s + mode->htotal/2;
+ vs2_line_s = vs1_line_s + mode->vtotal/2 ;
+ vs2_line_e = vs2_line_s +
+ (mode->vsync_end - mode->vsync_start)/2;
+ }
- DBG("clock=%d, div=%u", mode->clock, div);
- DBG("hs_start=%u, hs_end=%u, line_start=%u, line_end=%u",
- hs_start, hs_end, line_start, line_end);
- DBG("vwin_start=%u, vwin_end=%u, de_start=%u, de_end=%u",
- vwin_start, vwin_end, de_start, de_end);
- DBG("ref_line=%u, ref_pix=%u, pix_start2=%u",
- ref_line, ref_pix, pix_start2);
+ div = 148500 / mode->clock;
/* mute the audio FIFO: */
reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
@@ -561,9 +852,6 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
PLL_SERIAL_2_SRL_PR(rep));
- reg_write16(encoder, REG_VS_PIX_STRT_2_MSB, pix_start2);
- reg_write16(encoder, REG_VS_PIX_END_2_MSB, pix_start2);
-
/* set color matrix bypass flag: */
reg_set(encoder, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP);
@@ -572,47 +860,74 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD);
+ /*
+ * Sync on rising HSYNC/VSYNC
+ */
reg_write(encoder, REG_VIP_CNTRL_3, 0);
reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_SYNC_HS);
+
+ /*
+ * TDA19988 requires high-active sync at input stage,
+ * so invert low-active sync provided by master encoder here
+ */
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_H_TGL);
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_V_TGL);
+ /*
+ * Always generate sync polarity relative to input sync and
+ * revert input stage toggled sync at output stage
+ */
+ reg = TBG_CNTRL_1_TGL_EN;
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_H_TGL);
+ reg |= TBG_CNTRL_1_H_TGL;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ reg |= TBG_CNTRL_1_V_TGL;
+ reg_write(encoder, REG_TBG_CNTRL_1, reg);
reg_write(encoder, REG_VIDFORMAT, 0x00);
- reg_write16(encoder, REG_NPIX_MSB, mode->hdisplay - 1);
- reg_write16(encoder, REG_NLINE_MSB, mode->vdisplay - 1);
- reg_write16(encoder, REG_VS_LINE_STRT_1_MSB, line_start);
- reg_write16(encoder, REG_VS_LINE_END_1_MSB, line_end);
- reg_write16(encoder, REG_VS_PIX_STRT_1_MSB, hs_start);
- reg_write16(encoder, REG_VS_PIX_END_1_MSB, hs_start);
- reg_write16(encoder, REG_HS_PIX_START_MSB, hs_start);
- reg_write16(encoder, REG_HS_PIX_STOP_MSB, hs_end);
- reg_write16(encoder, REG_VWIN_START_1_MSB, vwin_start);
- reg_write16(encoder, REG_VWIN_END_1_MSB, vwin_end);
- reg_write16(encoder, REG_DE_START_MSB, de_start);
- reg_write16(encoder, REG_DE_STOP_MSB, de_end);
+ reg_write16(encoder, REG_REFPIX_MSB, ref_pix);
+ reg_write16(encoder, REG_REFLINE_MSB, ref_line);
+ reg_write16(encoder, REG_NPIX_MSB, n_pix);
+ reg_write16(encoder, REG_NLINE_MSB, n_line);
+ reg_write16(encoder, REG_VS_LINE_STRT_1_MSB, vs1_line_s);
+ reg_write16(encoder, REG_VS_PIX_STRT_1_MSB, vs1_pix_s);
+ reg_write16(encoder, REG_VS_LINE_END_1_MSB, vs1_line_e);
+ reg_write16(encoder, REG_VS_PIX_END_1_MSB, vs1_pix_e);
+ reg_write16(encoder, REG_VS_LINE_STRT_2_MSB, vs2_line_s);
+ reg_write16(encoder, REG_VS_PIX_STRT_2_MSB, vs2_pix_s);
+ reg_write16(encoder, REG_VS_LINE_END_2_MSB, vs2_line_e);
+ reg_write16(encoder, REG_VS_PIX_END_2_MSB, vs2_pix_e);
+ reg_write16(encoder, REG_HS_PIX_START_MSB, hs_pix_s);
+ reg_write16(encoder, REG_HS_PIX_STOP_MSB, hs_pix_e);
+ reg_write16(encoder, REG_VWIN_START_1_MSB, vwin1_line_s);
+ reg_write16(encoder, REG_VWIN_END_1_MSB, vwin1_line_e);
+ reg_write16(encoder, REG_VWIN_START_2_MSB, vwin2_line_s);
+ reg_write16(encoder, REG_VWIN_END_2_MSB, vwin2_line_e);
+ reg_write16(encoder, REG_DE_START_MSB, de_pix_s);
+ reg_write16(encoder, REG_DE_STOP_MSB, de_pix_e);
if (priv->rev == TDA19988) {
/* let incoming pixels fill the active space (if any) */
reg_write(encoder, REG_ENABLE_SPACE, 0x01);
}
- reg_write16(encoder, REG_REFPIX_MSB, ref_pix);
- reg_write16(encoder, REG_REFLINE_MSB, ref_line);
-
- reg = TBG_CNTRL_1_VHX_EXT_DE |
- TBG_CNTRL_1_VHX_EXT_HS |
- TBG_CNTRL_1_VHX_EXT_VS |
- TBG_CNTRL_1_DWIN_DIS | /* HDCP off */
- TBG_CNTRL_1_VH_TGL_2;
- if (mode->flags & (DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC))
- reg |= TBG_CNTRL_1_VH_TGL_0;
- reg_set(encoder, REG_TBG_CNTRL_1, reg);
-
/* must be last register set: */
reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE);
+
+ /* Only setup the info frames if the sink is HDMI */
+ if (priv->is_hdmi_sink) {
+ /* We need to turn HDMI HDCP stuff on to get audio through */
+ reg_clear(encoder, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
+ reg_write(encoder, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1));
+ reg_set(encoder, REG_TX33, TX33_HDMI);
+
+ tda998x_write_avi(encoder, adjusted_mode);
+
+ if (priv->params.audio_cfg)
+ tda998x_configure_audio(encoder, &priv->params);
+ }
}
static enum drm_connector_status
@@ -673,6 +988,7 @@ read_edid_block(struct drm_encoder *encoder, uint8_t *buf, int blk)
static uint8_t *
do_get_edid(struct drm_encoder *encoder)
{
+ struct tda998x_priv *priv = to_tda998x_priv(encoder);
int j = 0, valid_extensions = 0;
uint8_t *block, *new;
bool print_bad_edid = drm_debug & DRM_UT_KMS;
@@ -680,6 +996,9 @@ do_get_edid(struct drm_encoder *encoder)
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
return NULL;
+ if (priv->rev == TDA19988)
+ reg_clear(encoder, REG_TX4, TX4_PD_RAM);
+
/* base block fetch */
if (read_edid_block(encoder, block, 0))
goto fail;
@@ -689,7 +1008,7 @@ do_get_edid(struct drm_encoder *encoder)
/* if there's no extensions, we're done */
if (block[0x7e] == 0)
- return block;
+ goto done;
new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new)
@@ -716,9 +1035,15 @@ do_get_edid(struct drm_encoder *encoder)
block = new;
}
+done:
+ if (priv->rev == TDA19988)
+ reg_set(encoder, REG_TX4, TX4_PD_RAM);
+
return block;
fail:
+ if (priv->rev == TDA19988)
+ reg_set(encoder, REG_TX4, TX4_PD_RAM);
dev_warn(encoder->dev->dev, "failed to read EDID\n");
kfree(block);
return NULL;
@@ -728,12 +1053,14 @@ static int
tda998x_encoder_get_modes(struct drm_encoder *encoder,
struct drm_connector *connector)
{
+ struct tda998x_priv *priv = to_tda998x_priv(encoder);
struct edid *edid = (struct edid *)do_get_edid(encoder);
int n = 0;
if (edid) {
drm_mode_connector_update_edid_property(connector, edid);
n = drm_add_edid_modes(connector, edid);
+ priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid);
kfree(edid);
}
@@ -795,6 +1122,40 @@ tda998x_remove(struct i2c_client *client)
return 0;
}
+static ssize_t i2c_read_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct drm_encoder *encoder = dev_get_drvdata(dev);
+ unsigned int page, addr;
+ unsigned char val;
+
+ sscanf(buf, "%x %x", &page, &addr);
+
+ val = reg_read(encoder, REG(page, addr));
+
+ printk("i2c read %02x @ page:%02x address:%02x\n", val, page, addr);
+ return size;
+}
+
+static ssize_t i2c_write_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct drm_encoder *encoder = dev_get_drvdata(dev);
+ unsigned int page, addr, mask, val;
+ unsigned char rval;
+
+ sscanf(buf, "%x %x %x %x", &page, &addr, &mask, &val);
+
+ rval = reg_read(encoder, REG(page, addr));
+ rval &= ~mask;
+ rval |= val & mask;
+ reg_write(encoder, REG(page, addr), rval);
+
+ printk("i2c write %02x @ page:%02x address:%02x\n", rval, page, addr);
+ return size;
+}
+
+static DEVICE_ATTR(i2c_read, S_IWUSR, NULL, i2c_read_store);
+static DEVICE_ATTR(i2c_write, S_IWUSR, NULL, i2c_write_store);
+
static int
tda998x_encoder_init(struct i2c_client *client,
struct drm_device *dev,
@@ -802,11 +1163,20 @@ tda998x_encoder_init(struct i2c_client *client,
{
struct drm_encoder *encoder = &encoder_slave->base;
struct tda998x_priv *priv;
+/* debug */
+ device_create_file(&client->dev, &dev_attr_i2c_read);
+ device_create_file(&client->dev, &dev_attr_i2c_write);
+ dev_set_drvdata(&client->dev, encoder);
+/* debug end */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3);
+ priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);
+ priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
+
priv->current_page = 0;
priv->cec = i2c_new_dummy(client->adapter, 0x34);
priv->dpms = DRM_MODE_DPMS_OFF;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 7418dcd..2aab53e 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -69,7 +69,6 @@ static void set_scanout(struct drm_crtc *crtc, int n)
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct drm_device *dev = crtc->dev;
- pm_runtime_get_sync(dev->dev);
tilcdc_write(dev, base_reg[n], tilcdc_crtc->start);
tilcdc_write(dev, ceil_reg[n], tilcdc_crtc->end);
if (tilcdc_crtc->scanout[n]) {
@@ -85,7 +84,6 @@ static void set_scanout(struct drm_crtc *crtc, int n)
tilcdc_crtc->scanout[n] = crtc->fb;
drm_framebuffer_reference(tilcdc_crtc->scanout[n]);
tilcdc_crtc->dirty &= ~stat[n];
- pm_runtime_put_sync(dev->dev);
}
static void update_scanout(struct drm_crtc *crtc)
@@ -168,7 +166,9 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
crtc->fb = fb;
tilcdc_crtc->event = event;
+ pm_runtime_get_sync(dev->dev);
update_scanout(crtc);
+ pm_runtime_put_sync(dev->dev);
return 0;
}
@@ -379,7 +379,12 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
else
tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ /*
+ * use value from adjusted_mode here as this might have been changed as part
+ * of the fixup for NXP TDA998x to solve the issue where tilcdc timings are
+ * not VESA compliant
+ */
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC);
else
tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC);
@@ -406,7 +411,11 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
+ struct drm_device *dev = crtc->dev;
+
+ pm_runtime_get_sync(dev->dev);
update_scanout(crtc);
+ pm_runtime_put_sync(dev->dev);
return 0;
}
@@ -686,3 +695,59 @@ fail:
tilcdc_crtc_destroy(crtc);
return NULL;
}
+
+struct tilcdc_panel_info *tilcdc_of_get_panel_info(struct device_node *np)
+{
+ struct device_node *info_np;
+ struct tilcdc_panel_info *info;
+ int ret = 0;
+
+ if (!np)
+ return NULL;
+
+ info_np = of_get_child_by_name(np, "panel-info");
+ if (!info_np) {
+ pr_err("%s: could not find panel-info node\n",
+ of_node_full_name(np));
+ return NULL;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ pr_err("%s: allocation failed\n",
+ of_node_full_name(np));
+ goto err_no_mem;
+ }
+
+ ret |= of_property_read_u32(info_np, "ac-bias", &info->ac_bias);
+ ret |= of_property_read_u32(info_np, "ac-bias-intrpt", &info->ac_bias_intrpt);
+ ret |= of_property_read_u32(info_np, "dma-burst-sz", &info->dma_burst_sz);
+ ret |= of_property_read_u32(info_np, "bpp", &info->bpp);
+ ret |= of_property_read_u32(info_np, "fdd", &info->fdd);
+ ret |= of_property_read_u32(info_np, "sync-edge", &info->sync_edge);
+ ret |= of_property_read_u32(info_np, "sync-ctrl", &info->sync_ctrl);
+ ret |= of_property_read_u32(info_np, "raster-order", &info->raster_order);
+ ret |= of_property_read_u32(info_np, "fifo-th", &info->fifo_th);
+
+ /* optional: */
+ info->tft_alt_mode = of_property_read_bool(info_np, "tft-alt-mode");
+ info->invert_pxl_clk = of_property_read_bool(info_np, "invert-pxl-clk");
+
+ if (ret) {
+ pr_err("%s: error reading panel-info properties\n",
+ of_node_full_name(info_np));
+ goto err_bad_prop;
+ }
+
+ /* release ref */
+ of_node_put(info_np);
+
+ return info;
+
+err_bad_prop:
+ kfree(info);
+err_no_mem:
+ of_node_put(info_np);
+ return NULL;
+}
+
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 0938036..f5f00f1 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -43,7 +43,7 @@
* with optimized DDR & EMIF settings tweaked 1920x1080@24 appears to
* be supportable
*/
-#define TILCDC_DEFAULT_MAX_BANDWIDTH (1280*1024*60)
+#define TILCDC_DEFAULT_MAX_BANDWIDTH (1680*1050*60)
struct tilcdc_drm_private {
@@ -170,4 +170,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode);
int tilcdc_crtc_max_width(struct drm_crtc *crtc);
+/* OF helper for reading panel info */
+struct tilcdc_panel_info *tilcdc_of_get_panel_info(struct device_node *np);
+
#endif /* __TILCDC_DRV_H__ */
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index 86c6732..284c9ee 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -304,53 +304,6 @@ static const struct tilcdc_module_ops panel_module_ops = {
* Device:
*/
-/* maybe move this somewhere common if it is needed by other outputs? */
-static struct tilcdc_panel_info *of_get_panel_info(struct device_node *np)
-{
- struct device_node *info_np;
- struct tilcdc_panel_info *info;
- int ret = 0;
-
- if (!np) {
- pr_err("%s: no devicenode given\n", __func__);
- return NULL;
- }
-
- info_np = of_get_child_by_name(np, "panel-info");
- if (!info_np) {
- pr_err("%s: could not find panel-info node\n", __func__);
- return NULL;
- }
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info) {
- pr_err("%s: allocation failed\n", __func__);
- return NULL;
- }
-
- ret |= of_property_read_u32(info_np, "ac-bias", &info->ac_bias);
- ret |= of_property_read_u32(info_np, "ac-bias-intrpt", &info->ac_bias_intrpt);
- ret |= of_property_read_u32(info_np, "dma-burst-sz", &info->dma_burst_sz);
- ret |= of_property_read_u32(info_np, "bpp", &info->bpp);
- ret |= of_property_read_u32(info_np, "fdd", &info->fdd);
- ret |= of_property_read_u32(info_np, "sync-edge", &info->sync_edge);
- ret |= of_property_read_u32(info_np, "sync-ctrl", &info->sync_ctrl);
- ret |= of_property_read_u32(info_np, "raster-order", &info->raster_order);
- ret |= of_property_read_u32(info_np, "fifo-th", &info->fifo_th);
-
- /* optional: */
- info->tft_alt_mode = of_property_read_bool(info_np, "tft-alt-mode");
- info->invert_pxl_clk = of_property_read_bool(info_np, "invert-pxl-clk");
-
- if (ret) {
- pr_err("%s: error reading panel-info properties\n", __func__);
- kfree(info);
- return NULL;
- }
-
- return info;
-}
-
static struct of_device_id panel_of_match[];
static int panel_probe(struct platform_device *pdev)
@@ -387,7 +340,7 @@ static int panel_probe(struct platform_device *pdev)
goto fail;
}
- panel_mod->info = of_get_panel_info(node);
+ panel_mod->info = tilcdc_of_get_panel_info(node);
if (!panel_mod->info) {
dev_err(&pdev->dev, "could not get panel info\n");
goto fail;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
index dfffaf0..4bdc9ba 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
@@ -25,23 +25,11 @@
struct slave_module {
struct tilcdc_module base;
+ struct tilcdc_panel_info *info;
struct i2c_adapter *i2c;
};
#define to_slave_module(x) container_of(x, struct slave_module, base)
-static const struct tilcdc_panel_info slave_info = {
- .bpp = 16,
- .ac_bias = 255,
- .ac_bias_intrpt = 0,
- .dma_burst_sz = 16,
- .fdd = 0x80,
- .tft_alt_mode = 0,
- .sync_edge = 0,
- .sync_ctrl = 1,
- .raster_order = 0,
-};
-
-
/*
* Encoder:
*/
@@ -69,17 +57,38 @@ static void slave_encoder_destroy(struct drm_encoder *encoder)
static void slave_encoder_prepare(struct drm_encoder *encoder)
{
+ struct slave_encoder *slave_encoder = to_slave_encoder(encoder);
+
drm_i2c_encoder_prepare(encoder);
- tilcdc_crtc_set_panel_info(encoder->crtc, &slave_info);
+ tilcdc_crtc_set_panel_info(encoder->crtc, slave_encoder->mod->info);
+}
+
+static bool slave_encoder_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ adjusted_mode->hskew = mode->hsync_end - mode->hsync_start;
+ adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW;
+
+ if(mode->flags & DRM_MODE_FLAG_NHSYNC) {
+ adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC;
+ } else {
+ adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ adjusted_mode->flags &= ~DRM_MODE_FLAG_PHSYNC;
+ }
+
+ return drm_i2c_encoder_mode_fixup(encoder, mode, adjusted_mode);
}
+
static const struct drm_encoder_funcs slave_encoder_funcs = {
.destroy = slave_encoder_destroy,
};
static const struct drm_encoder_helper_funcs slave_encoder_helper_funcs = {
.dpms = drm_i2c_encoder_dpms,
- .mode_fixup = drm_i2c_encoder_mode_fixup,
+ .mode_fixup = slave_encoder_fixup,
.prepare = slave_encoder_prepare,
.commit = drm_i2c_encoder_commit,
.mode_set = drm_i2c_encoder_mode_set,
@@ -276,6 +285,7 @@ static void slave_destroy(struct tilcdc_module *mod)
struct slave_module *slave_mod = to_slave_module(mod);
tilcdc_module_cleanup(mod);
+ kfree(slave_mod->info);
kfree(slave_mod);
}
@@ -330,13 +340,25 @@ static int slave_probe(struct platform_device *pdev)
return ret;
}
- slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL);
- if (!slave_mod)
- return -ENOMEM;
+ slave_mod = devm_kzalloc(&pdev->dev, sizeof(*slave_mod), GFP_KERNEL);
+ if (!slave_mod) {
+ tilcdc_slave_probedefer(false);
+ dev_err(&pdev->dev, "could not allocate slave_mod\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, slave_mod);
+
+ slave_mod->info = tilcdc_of_get_panel_info(node);
+ if (!slave_mod->info) {
+ tilcdc_slave_probedefer(false);
+ dev_err(&pdev->dev, "could not get panel info\n");
+ return ret;
+ }
mod = &slave_mod->base;
- mod->preferred_bpp = slave_info.bpp;
+ mod->preferred_bpp = slave_mod->info->bpp;
slave_mod->i2c = slavei2c;
@@ -353,6 +375,11 @@ static int slave_probe(struct platform_device *pdev)
static int slave_remove(struct platform_device *pdev)
{
+ struct slave_module *slave_mod = platform_get_drvdata(pdev);
+
+ put_device(&slave_mod->i2c->dev);
+ kfree(slave_mod->info);
+
return 0;
}
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 5d4fd69..7e0474d 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -23,6 +23,7 @@
#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
+#include <linux/i2c/eeprom.h>
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
@@ -658,6 +659,27 @@ static int at24_remove(struct i2c_client *client)
return 0;
}
+static int at24_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct at24_data *at24;
+ const struct memory_accessor **maccp;
+
+ /* only supporting a single command */
+ if (cmd != I2C_EEPROM_GET_MEMORY_ACCESSOR)
+ return -ENOTSUPP;
+
+ /* rudimentary check */
+ if (arg == NULL)
+ return -EINVAL;
+
+ at24 = i2c_get_clientdata(client);
+
+ maccp = arg;
+ *maccp = &at24->macc;
+
+ return 0;
+}
+
/*-------------------------------------------------------------------------*/
static struct i2c_driver at24_driver = {
@@ -668,6 +690,7 @@ static struct i2c_driver at24_driver = {
.probe = at24_probe,
.remove = at24_remove,
.id_table = at24_ids,
+ .command = at24_command,
};
static int __init at24_init(void)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 1865321..1fe7469 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -40,6 +40,8 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mmc-omap.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/err.h>
/* OMAP HSMMC Host Controller Registers */
#define OMAP_HSMMC_SYSSTATUS 0x0014
@@ -171,7 +173,7 @@ struct omap_hsmmc_host {
unsigned char power_mode;
int suspended;
int irq;
- int use_dma, dma_ch;
+ int use_dma;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
int slot_id;
@@ -180,10 +182,15 @@ struct omap_hsmmc_host {
int protect_card;
int reqs_blocked;
int use_reg;
- int req_in_progress;
struct omap_hsmmc_next next_data;
struct omap_mmc_platform_data *pdata;
+
+ unsigned int req_flags;
+#define RQF_REQ_IN_PROGRESS (1 << 0)
+#define RQF_DMA_IN_PROGRESS (1 << 1)
+#define RQF_REQ_DONE (1 << 2)
+#define RQF_DMA_DONE (1 << 3)
};
static int omap_hsmmc_card_detect(struct device *dev, int slot)
@@ -391,6 +398,7 @@ static inline int omap_hsmmc_have_reg(void)
static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
{
int ret;
+ unsigned long flags;
if (gpio_is_valid(pdata->slots[0].switch_pin)) {
if (pdata->slots[0].cover)
@@ -420,6 +428,24 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
} else
pdata->slots[0].gpio_wp = -EINVAL;
+ if (gpio_is_valid(pdata->slots[0].gpio_reset)) {
+ flags = pdata->slots[0].gpio_reset_active_low ?
+ GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
+ ret = gpio_request_one(pdata->slots[0].gpio_reset, flags,
+ "mmc_reset");
+ if (ret)
+ goto err_free_wp;
+
+ /* hold reset */
+ udelay(pdata->slots[0].gpio_reset_hold_us);
+
+ gpio_set_value(pdata->slots[0].gpio_reset,
+ !pdata->slots[0].gpio_reset_active_low);
+
+ } else
+ pdata->slots[0].gpio_reset = -EINVAL;
+
+
return 0;
err_free_wp:
@@ -433,6 +459,8 @@ err_free_sp:
static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
{
+ if (gpio_is_valid(pdata->slots[0].gpio_reset))
+ gpio_free(pdata->slots[0].gpio_reset);
if (gpio_is_valid(pdata->slots[0].gpio_wp))
gpio_free(pdata->slots[0].gpio_wp);
if (gpio_is_valid(pdata->slots[0].switch_pin))
@@ -787,7 +815,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
* ac, bc, adtc, bcr. Only commands ending an open ended transfer need
* a val of 0x3, rest 0x0.
*/
- if (cmd == host->mrq->stop)
+ if (host->mrq && cmd == host->mrq->stop)
cmdtype = 0x3;
cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
@@ -803,7 +831,8 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
if (host->use_dma)
cmdreg |= DMAE;
- host->req_in_progress = 1;
+ host->req_flags |= RQF_REQ_IN_PROGRESS;
+ host->req_flags &= ~RQF_REQ_DONE;
OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -826,19 +855,36 @@ static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
{
- int dma_ch;
+ int completed;
unsigned long flags;
+ BUG_ON(mrq == NULL);
+
spin_lock_irqsave(&host->irq_lock, flags);
- host->req_in_progress = 0;
- dma_ch = host->dma_ch;
- spin_unlock_irqrestore(&host->irq_lock, flags);
+
+ host->req_flags &= ~RQF_REQ_IN_PROGRESS;
+ host->req_flags |= RQF_REQ_DONE;
+
+ /* completed? */
+ if (mrq->data && host->use_dma)
+ completed = (host->req_flags & RQF_DMA_DONE) == RQF_DMA_DONE;
+ else
+ completed = 1;
omap_hsmmc_disable_irq(host);
+
/* Do not complete the request if DMA is still in progress */
- if (mrq->data && host->use_dma && dma_ch != -1)
+ if (!completed) {
+ spin_unlock_irqrestore(&host->irq_lock, flags);
+ pr_debug("%s: not completed!\n", __func__);
return;
+ }
+
+ /* clear the flags now */
+ host->req_flags &= ~(RQF_REQ_DONE | RQF_DMA_DONE);
host->mrq = NULL;
+ spin_unlock_irqrestore(&host->irq_lock, flags);
+
mmc_request_done(host->mmc, mrq);
}
@@ -855,6 +901,7 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
if (host->cmd && host->cmd->opcode == 6 &&
host->response_busy) {
host->response_busy = 0;
+ pr_debug("%s: response_busy = 0\n", __func__);
return;
}
@@ -870,9 +917,11 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
data->bytes_xfered = 0;
if (!data->stop) {
+ pr_debug("%s: calling omap_hsmmc_request_done\n", __func__);
omap_hsmmc_request_done(host, data->mrq);
return;
}
+ pr_debug("%s: calling omap_hsmmc_start_command\n", __func__);
omap_hsmmc_start_command(host, data->stop, NULL);
}
@@ -882,6 +931,8 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
static void
omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
{
+ unsigned long flags;
+
host->cmd = NULL;
if (cmd->flags & MMC_RSP_PRESENT) {
@@ -898,6 +949,18 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
}
if ((host->data == NULL && !host->response_busy) || cmd->error)
omap_hsmmc_request_done(host, cmd->mrq);
+ else {
+ spin_lock_irqsave(&host->irq_lock, flags);
+ /* we use DMA, and DMA is completed - kick the can */
+ if ((host->req_flags & RQF_DMA_DONE) != 0) {
+ host->req_flags &= ~(RQF_REQ_IN_PROGRESS | RQF_REQ_DONE | RQF_DMA_DONE);
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, cmd->mrq);
+ } else {
+ pr_debug("%s: not calling omap_hsmmc_request_done!\n", __func__);
+ }
+ spin_unlock_irqrestore(&host->irq_lock, flags);
+ }
}
/*
@@ -905,17 +968,19 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
*/
static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
{
- int dma_ch;
+ int dma_in_progress;
unsigned long flags;
host->data->error = errno;
spin_lock_irqsave(&host->irq_lock, flags);
- dma_ch = host->dma_ch;
- host->dma_ch = -1;
+ dma_in_progress = host->use_dma &&
+ (host->req_flags & RQF_DMA_IN_PROGRESS) != 0;
+ host->req_flags &= ~RQF_DMA_IN_PROGRESS;
+ host->req_flags |= RQF_DMA_DONE;
spin_unlock_irqrestore(&host->irq_lock, flags);
- if (host->use_dma && dma_ch != -1) {
+ if (dma_in_progress) {
struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data);
dmaengine_terminate_all(chan);
@@ -1005,16 +1070,22 @@ static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
int err, int end_cmd)
{
if (end_cmd) {
+ pr_debug("%s end_cmd\n", __func__);
omap_hsmmc_reset_controller_fsm(host, SRC);
if (host->cmd)
host->cmd->error = err;
}
if (host->data) {
+ pr_debug("%s host->data; resetting dma\n", __func__);
omap_hsmmc_reset_controller_fsm(host, SRD);
omap_hsmmc_dma_cleanup(host, err);
- } else if (host->mrq && host->mrq->cmd)
+ } else if (host->mrq && host->mrq->cmd) {
+ pr_debug("%s error\n", __func__);
host->mrq->cmd->error = err;
+ } else {
+ pr_debug("%s nothing\n", __func__);
+ }
}
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
@@ -1055,13 +1126,13 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
struct omap_hsmmc_host *host = dev_id;
int status;
- status = OMAP_HSMMC_READ(host->base, STAT);
- while (status & INT_EN_MASK && host->req_in_progress) {
- omap_hsmmc_do_irq(host, status);
+ while ((status = OMAP_HSMMC_READ(host->base, STAT)) & INT_EN_MASK) {
+
+ if (host->req_flags & RQF_REQ_IN_PROGRESS)
+ omap_hsmmc_do_irq(host, status);
/* Flush posted write */
OMAP_HSMMC_WRITE(host->base, STAT, status);
- status = OMAP_HSMMC_READ(host->base, STAT);
}
return IRQ_HANDLED;
@@ -1199,13 +1270,15 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
static void omap_hsmmc_dma_callback(void *param)
{
struct omap_hsmmc_host *host = param;
+ struct mmc_request *mrq = host->mrq;
struct dma_chan *chan;
struct mmc_data *data;
- int req_in_progress;
+ int completed;
spin_lock_irq(&host->irq_lock);
- if (host->dma_ch < 0) {
+ if ((host->req_flags & RQF_DMA_IN_PROGRESS) == 0) {
spin_unlock_irq(&host->irq_lock);
+ pr_debug("%s: No DMA in progress!\n", __func__);
return;
}
@@ -1216,17 +1289,22 @@ static void omap_hsmmc_dma_callback(void *param)
data->sg, data->sg_len,
omap_hsmmc_get_dma_dir(host, data));
- req_in_progress = host->req_in_progress;
- host->dma_ch = -1;
- spin_unlock_irq(&host->irq_lock);
+ host->req_flags &= ~RQF_DMA_IN_PROGRESS;
+ host->req_flags |= RQF_DMA_DONE;
- /* If DMA has finished after TC, complete the request */
- if (!req_in_progress) {
- struct mmc_request *mrq = host->mrq;
+ completed = (host->req_flags & RQF_REQ_DONE) != 0;
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
+ if (!completed) {
+ spin_unlock_irq(&host->irq_lock);
+ pr_debug("%s: not completed\n", __func__);
+ return;
}
+
+ host->req_flags &= ~(RQF_REQ_DONE | RQF_DMA_DONE);
+ host->mrq = NULL;
+ spin_unlock_irq(&host->irq_lock);
+
+ mmc_request_done(host->mmc, mrq);
}
static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
@@ -1294,7 +1372,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
*/
return -EINVAL;
- BUG_ON(host->dma_ch != -1);
+ BUG_ON((host->req_flags & RQF_DMA_IN_PROGRESS) != 0);
chan = omap_hsmmc_get_dma_chan(host, data);
@@ -1328,7 +1406,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
/* Does not fail */
dmaengine_submit(tx);
- host->dma_ch = 1;
+ host->req_flags |= RQF_DMA_IN_PROGRESS;
dma_async_issue_pending(chan);
@@ -1448,8 +1526,11 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
struct omap_hsmmc_host *host = mmc_priv(mmc);
int err;
- BUG_ON(host->req_in_progress);
- BUG_ON(host->dma_ch != -1);
+ BUG_ON((host->req_flags & RQF_REQ_IN_PROGRESS) != 0);
+ BUG_ON((host->req_flags & RQF_REQ_DONE) != 0);
+ BUG_ON((host->req_flags & RQF_DMA_IN_PROGRESS) != 0);
+ BUG_ON((host->req_flags & RQF_DMA_DONE) != 0);
+
if (host->protect_card) {
if (host->reqs_blocked < 3) {
/*
@@ -1719,6 +1800,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
struct device_node *np = dev->of_node;
u32 bus_width, max_freq;
int cd_gpio, wp_gpio;
+ enum of_gpio_flags reset_flags;
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
@@ -1736,6 +1818,14 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
pdata->nr_slots = 1;
pdata->slots[0].switch_pin = cd_gpio;
pdata->slots[0].gpio_wp = wp_gpio;
+ reset_flags = 0;
+ pdata->slots[0].gpio_reset = of_get_named_gpio_flags(np,
+ "reset-gpios", 0, &reset_flags);
+ pdata->slots[0].gpio_reset_active_low =
+ (reset_flags & OF_GPIO_ACTIVE_LOW) != 0;
+ pdata->slots[0].gpio_reset_hold_us = 100; /* default */
+ of_property_read_u32(np, "reset-gpio-hold-us",
+ &pdata->slots[0].gpio_reset_hold_us);
if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->slots[0].nonremovable = true;
@@ -1776,6 +1866,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
const struct of_device_id *match;
dma_cap_mask_t mask;
unsigned tx_req, rx_req;
+ struct dma_slave_sg_limits *dma_sg_limits;
struct pinctrl *pinctrl;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
@@ -1801,6 +1892,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
return -ENXIO;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev, "unable to select pin group\n");
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (res == NULL || irq < 0)
@@ -1825,13 +1920,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->pdata = pdata;
host->dev = &pdev->dev;
host->use_dma = 1;
- host->dma_ch = -1;
host->irq = irq;
host->slot_id = 0;
host->mapbase = res->start + pdata->reg_offset;
host->base = ioremap(host->mapbase, SZ_4K);
host->power_mode = MMC_POWER_OFF;
host->next_data.cookie = 1;
+ host->req_flags = 0;
platform_set_drvdata(pdev, host);
@@ -1892,6 +1987,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
* as we want. */
mmc->max_segs = 1024;
+ /* Eventually we should get our max_segs limitation for EDMA by
+ * querying the dmaengine API */
+ if (pdev->dev.of_node) {
+ struct device_node *parent = of_node_get(pdev->dev.of_node->parent);
+ struct device_node *node;
+ node = of_find_node_by_name(parent, "edma");
+ if (node)
+ mmc->max_segs = 16;
+ }
+
mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
@@ -1952,6 +2057,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq;
}
+ /* Some DMA Engines only handle a limited number of SG segments */
+ dma_sg_limits = dma_get_slave_sg_limits(host->rx_chan,
+ DMA_SLAVE_BUSWIDTH_4_BYTES,
+ mmc->max_blk_size / 4);
+ if (dma_sg_limits && dma_sg_limits->max_seg_nr)
+ mmc->max_segs = dma_sg_limits->max_seg_nr;
+
/* Request IRQ for MMC operations */
ret = request_irq(host->irq, omap_hsmmc_irq, 0,
mmc_hostname(mmc), host);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index f685e55..b4b95c6 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -63,6 +63,9 @@ int of_device_add(struct platform_device *ofdev)
if (!ofdev->dev.parent)
set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));
+ /* make sure we add the resources to the appropriate lists */
+ platform_device_link_resources(ofdev);
+
return device_add(&ofdev->dev);
}
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index b667264..116a5e0 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -17,10 +17,64 @@
#include <linux/of_i2c.h>
#include <linux/of_irq.h>
#include <linux/module.h>
+#include <linux/err.h>
+
+struct i2c_client *
+of_i2c_register_device(struct i2c_adapter *adap,
+ struct device_node *node)
+{
+ struct i2c_client *result;
+ struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
+ const __be32 *addr;
+ int len;
+
+ dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
+
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+ dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
+ node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ addr = of_get_property(node, "reg", &len);
+ if (!addr || (len < sizeof(int))) {
+ dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
+ node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ info.addr = be32_to_cpup(addr);
+ if (info.addr > (1 << 10) - 1) {
+ dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
+ info.addr, node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+ info.archdata = &dev_ad;
+
+ if (of_get_property(node, "wakeup-source", NULL))
+ info.flags |= I2C_CLIENT_WAKE;
+
+ request_module("%s%s", I2C_MODULE_PREFIX, info.type);
+
+ result = i2c_new_device(adap, &info);
+ if (result == NULL) {
+ dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+ node->full_name);
+ of_node_put(node);
+ irq_dispose_mapping(info.irq);
+ return ERR_PTR(-ENODEV);
+ }
+
+ return result;
+}
+EXPORT_SYMBOL(of_i2c_register_device);
void of_i2c_register_devices(struct i2c_adapter *adap)
{
- void *result;
struct device_node *node;
/* Only register child devices if the adapter has a node pointer set */
@@ -29,52 +83,8 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
- for_each_available_child_of_node(adap->dev.of_node, node) {
- struct i2c_board_info info = {};
- struct dev_archdata dev_ad = {};
- const __be32 *addr;
- int len;
-
- dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
-
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
- dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
- node->full_name);
- continue;
- }
-
- addr = of_get_property(node, "reg", &len);
- if (!addr || (len < sizeof(int))) {
- dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
- node->full_name);
- continue;
- }
-
- info.addr = be32_to_cpup(addr);
- if (info.addr > (1 << 10) - 1) {
- dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
- info.addr, node->full_name);
- continue;
- }
-
- info.irq = irq_of_parse_and_map(node, 0);
- info.of_node = of_node_get(node);
- info.archdata = &dev_ad;
-
- if (of_get_property(node, "wakeup-source", NULL))
- info.flags |= I2C_CLIENT_WAKE;
-
- request_module("%s%s", I2C_MODULE_PREFIX, info.type);
-
- result = i2c_new_device(adap, &info);
- if (result == NULL) {
- dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
- node->full_name);
- of_node_put(node);
- irq_dispose_mapping(info.irq);
- continue;
- }
- }
+ for_each_available_child_of_node(adap->dev.of_node, node)
+ of_i2c_register_device(adap, node);
}
EXPORT_SYMBOL(of_i2c_register_devices);
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 7323cca..ff08c27 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1662,7 +1662,17 @@ static struct platform_driver pcs_driver = {
#endif
};
-module_platform_driver(pcs_driver);
+static int __init pcs_init(void)
+{
+ return platform_driver_register(&pcs_driver);
+}
+postcore_initcall(pcs_init);
+
+static void __exit pcs_exit(void)
+{
+ platform_driver_unregister(&pcs_driver);
+}
+module_exit(pcs_exit);
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
MODULE_DESCRIPTION("One-register-per-pin type device tree based pinctrl driver");
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c9d04f7..1a862df 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -11,3 +11,14 @@ menuconfig RESET_CONTROLLER
via GPIOs or SoC-internal reset controller modules.
If unsure, say no.
+
+if RESET_CONTROLLER
+
+config RESET_GPIO
+ tristate "GPIO reset controller support"
+ depends on GPIOLIB && OF
+ help
+ This driver provides support for reset lines that are controlled
+ directly by GPIOs.
+
+endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 1e2d83f..b854f20 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_RESET_CONTROLLER) += core.o
+obj-$(CONFIG_RESET_GPIO) += gpio-reset.o
diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
new file mode 100644
index 0000000..acc1076
--- /dev/null
+++ b/drivers/reset/gpio-reset.c
@@ -0,0 +1,169 @@
+/*
+ * GPIO Reset Controller driver
+ *
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+struct gpio_reset_data {
+ struct reset_controller_dev rcdev;
+ unsigned int gpio;
+ bool active_low;
+ u32 delay_us;
+};
+
+static void __gpio_reset_set(struct reset_controller_dev *rcdev, int asserted)
+{
+ struct gpio_reset_data *drvdata = container_of(rcdev,
+ struct gpio_reset_data, rcdev);
+ int value = asserted;
+
+ if (drvdata->active_low)
+ value = !value;
+
+ gpio_set_value(drvdata->gpio, value);
+}
+
+static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct gpio_reset_data *drvdata = container_of(rcdev,
+ struct gpio_reset_data, rcdev);
+
+ if (drvdata->delay_us < 0)
+ return -ENOSYS;
+
+ __gpio_reset_set(rcdev, 1);
+ udelay(drvdata->delay_us);
+ __gpio_reset_set(rcdev, 0);
+
+ return 0;
+}
+
+static int gpio_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ __gpio_reset_set(rcdev, 1);
+
+ return 0;
+}
+
+static int gpio_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ __gpio_reset_set(rcdev, 0);
+
+ return 0;
+}
+
+static struct reset_control_ops gpio_reset_ops = {
+ .reset = gpio_reset,
+ .assert = gpio_reset_assert,
+ .deassert = gpio_reset_deassert,
+};
+
+static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ if (WARN_ON(reset_spec->args_count != 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int gpio_reset_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct gpio_reset_data *drvdata;
+ enum of_gpio_flags flags;
+ unsigned long gpio_flags;
+ bool initially_in_reset;
+ int ret;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (drvdata == NULL)
+ return -ENOMEM;
+
+ if (of_gpio_named_count(np, "reset-gpios") != 1)
+ return -EINVAL;
+
+ drvdata->gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
+ if (drvdata->gpio == -EPROBE_DEFER) {
+ return drvdata->gpio;
+ } else if (!gpio_is_valid(drvdata->gpio)) {
+ dev_err(&pdev->dev, "invalid reset gpio: %d\n", drvdata->gpio);
+ return drvdata->gpio;
+ }
+
+ drvdata->active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+ ret = of_property_read_u32(np, "reset-delay-us", &drvdata->delay_us);
+ if (ret < 0)
+ return ret;
+
+ initially_in_reset = of_property_read_bool(np, "initially-in-reset");
+ if (drvdata->active_low ^ initially_in_reset)
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
+ else
+ gpio_flags = GPIOF_OUT_INIT_LOW;
+
+ ret = devm_gpio_request_one(&pdev->dev, drvdata->gpio, gpio_flags, NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request gpio %d: %d\n",
+ drvdata->gpio, ret);
+ return ret;
+ }
+
+ drvdata->rcdev.of_node = np;
+ drvdata->rcdev.owner = THIS_MODULE;
+ drvdata->rcdev.nr_resets = 1;
+ drvdata->rcdev.ops = &gpio_reset_ops;
+ drvdata->rcdev.of_xlate = of_gpio_reset_xlate;
+ reset_controller_register(&drvdata->rcdev);
+
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0;
+}
+
+static int gpio_reset_remove(struct platform_device *pdev)
+{
+ struct gpio_reset_data *drvdata = platform_get_drvdata(pdev);
+
+ reset_controller_unregister(&drvdata->rcdev);
+
+ return 0;
+}
+
+static struct of_device_id gpio_reset_dt_ids[] = {
+ { .compatible = "gpio-reset" },
+ { }
+};
+
+static struct platform_driver gpio_reset_driver = {
+ .probe = gpio_reset_probe,
+ .remove = gpio_reset_remove,
+ .driver = {
+ .name = "gpio-reset",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_reset_dt_ids),
+ },
+};
+
+module_platform_driver(gpio_reset_driver);
+
+MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
+MODULE_DESCRIPTION("gpio reset controller");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-reset");
+MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids);
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 238c5d4..2b3132e 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -45,7 +45,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
-obj-$(CONFIG_USB_PHY) += phy/
+obj-$(CONFIG_USB_SUPPORT) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 8ce9d7f..a179c5a 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -20,7 +20,7 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -34,13 +34,13 @@ struct dwc3_exynos {
static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
{
- struct nop_usb_xceiv_platform_data pdata;
+ struct usb_phy_gen_xceiv_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;
@@ -51,7 +51,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
if (ret)
goto err1;
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
if (!pdev) {
ret = -ENOMEM;
goto err1;
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index ed07ec0..87ea3d5 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -43,7 +43,7 @@
#include <linux/platform_device.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
@@ -58,13 +58,13 @@ struct dwc3_pci {
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
{
- struct nop_usb_xceiv_platform_data pdata;
+ struct usb_phy_gen_xceiv_platform_data pdata;
struct platform_device *pdev;
int ret;
memset(&pdata, 0x00, sizeof(pdata));
- pdev = platform_device_alloc("nop_usb_xceiv", 0);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", 0);
if (!pdev)
return -ENOMEM;
@@ -75,7 +75,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue)
if (ret)
goto err1;
- pdev = platform_device_alloc("nop_usb_xceiv", 1);
+ pdev = platform_device_alloc("usb_phy_gen_xceiv", 1);
if (!pdev) {
ret = -ENOMEM;
goto err1;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 8e93683..7ec7283 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -144,7 +144,6 @@ config USB_AT91
config USB_LPC32XX
tristate "LPC32XX USB Peripheral Controller"
depends on ARCH_LPC32XX
- depends on USB_PHY
select USB_ISP1301
help
This option selects the USB device controller in the LPC32xx SoC.
@@ -206,7 +205,6 @@ config USB_FOTG210_UDC
config USB_OMAP
tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1
- depends on USB_PHY
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
help
Many Texas Instruments OMAP processors have flexible full
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 4263d01..3102b52 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -186,7 +186,6 @@ config USB_EHCI_HCD_AT91
config USB_EHCI_MSM
tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller"
depends on ARCH_MSM
- depends on USB_PHY
select USB_EHCI_ROOT_HUB_TT
select USB_MSM_OTG
---help---
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 2231850..5733a20 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -33,7 +33,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/platform_data/usb-omap.h>
#include "musb_core.h"
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 6ba8439..195e966 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <asm/cacheflush.h>
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 0da6f64..ccc6b63 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -33,7 +33,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <mach/da8xx.h>
#include <linux/platform_data/usb-davinci.h>
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index f8aeaf2..91f300e 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -33,7 +33,7 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <mach/cputype.h>
#include <mach/hardware.h>
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 5233804..55fe3c2 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -36,7 +36,7 @@
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include <linux/platform_data/usb-omap.h>
#include <linux/sizes.h>
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 6f8a9ca..c642f09 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -25,7 +25,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
#include "musb_core.h"
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 3622fff..f41c3e1 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -1,22 +1,10 @@
#
# Physical Layer USB driver configuration
#
-menuconfig USB_PHY
- bool "USB Physical Layer drivers"
- help
- Most USB controllers have the physical layer signalling part
- (commonly called a PHY) built in. However, dual-role devices
- (a.k.a. USB on-the-go) which support being USB master or slave
- with the same connector often use an external PHY.
-
- The drivers in this submenu add support for such PHY devices.
- They are not needed for standard master-only (or the vast
- majority of slave-only) USB interfaces.
+menu "USB Physical Layer drivers"
- If you're not sure if this applies to you, it probably doesn't;
- say N here.
-
-if USB_PHY
+config USB_PHY
+ def_bool n
#
# USB Transceiver Drivers
@@ -24,6 +12,7 @@ if USB_PHY
config AB8500_USB
tristate "AB8500 USB Transceiver Driver"
depends on AB8500_CORE
+ select USB_PHY
help
Enable this to support the USB OTG transceiver in AB8500 chip.
This transceiver supports high and full speed devices plus,
@@ -33,12 +22,14 @@ config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME
select USB_OTG
+ select USB_PHY
help
Enable this to support Freescale USB OTG transceiver.
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
+ select USB_PHY
help
If you say yes here you get support for the Philips ISP1301
USB-On-The-Go transceiver working with the OMAP OTG controller.
@@ -52,12 +43,14 @@ config ISP1301_OMAP
config MV_U3D_PHY
bool "Marvell USB 3.0 PHY controller Driver"
depends on CPU_MMP3
+ select USB_PHY
help
Enable this to support Marvell USB 3.0 phy controller for Marvell
SoC.
config NOP_USB_XCEIV
tristate "NOP USB Transceiver Driver"
+ select USB_PHY
help
This driver is to be used by all the usb transceiver which are either
built-in with usb ip or which are autonomous and doesn't require any
@@ -76,6 +69,7 @@ config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
select OMAP_CONTROL_USB
+ select USB_PHY
help
Enable this to support the transceiver that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
@@ -85,12 +79,25 @@ config OMAP_USB2
config OMAP_USB3
tristate "OMAP USB3 PHY Driver"
select OMAP_CONTROL_USB
+ select USB_PHY
help
Enable this to support the USB3 PHY that is part of SOC. This
driver takes care of all the PHY functionality apart from comparator.
This driver interacts with the "OMAP Control USB Driver" to power
on/off the PHY.
+config AM335X_CONTROL_USB
+ tristate
+
+config AM335X_PHY_USB
+ tristate "AM335x USB PHY Driver"
+ select USB_PHY
+ select AM335X_CONTROL_USB
+ select NOP_USB_XCEIV
+ help
+ This driver provides PHY support for that phy which part for the
+ AM335x SoC.
+
config SAMSUNG_USBPHY
tristate
help
@@ -101,6 +108,7 @@ config SAMSUNG_USBPHY
config SAMSUNG_USB2PHY
tristate "Samsung USB 2.0 PHY controller Driver"
select SAMSUNG_USBPHY
+ select USB_PHY
help
Enable this to support Samsung USB 2.0 (High Speed) PHY controller
driver for Samsung SoCs.
@@ -108,6 +116,7 @@ config SAMSUNG_USB2PHY
config SAMSUNG_USB3PHY
tristate "Samsung USB 3.0 PHY controller Driver"
select SAMSUNG_USBPHY
+ select USB_PHY
help
Enable this to support Samsung USB 3.0 (Super Speed) phy controller
for samsung SoCs.
@@ -115,6 +124,7 @@ config SAMSUNG_USB3PHY
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+ select USB_PHY
help
Enable this to support the USB OTG transceiver on TWL4030
family chips (including the TWL5030 and TPS659x0 devices).
@@ -135,6 +145,7 @@ config TWL6030_USB
config USB_GPIO_VBUS
tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
depends on GPIOLIB
+ select USB_PHY
help
Provides simple GPIO VBUS sensing for controllers with an
internal transceiver via the usb_phy interface, and
@@ -145,6 +156,7 @@ config USB_ISP1301
tristate "NXP ISP1301 USB transceiver support"
depends on USB || USB_GADGET
depends on I2C
+ select USB_PHY
help
Say Y here to add support for the NXP ISP1301 USB transceiver driver.
This chip is typically used as USB transceiver for USB host, gadget
@@ -156,6 +168,7 @@ config USB_ISP1301
config USB_MSM_OTG
tristate "OTG support for Qualcomm on-chip USB controller"
depends on (USB || USB_GADGET) && ARCH_MSM
+ select USB_PHY
help
Enable this to support the USB OTG transceiver on MSM chips. It
handles PHY initialization, clock management, and workarounds
@@ -169,6 +182,7 @@ config USB_MV_OTG
tristate "Marvell USB OTG support"
depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME
select USB_OTG
+ select USB_PHY
help
Say Y here if you want to build Marvell USB OTG transciever
driver in kernel (including PXA and MMP series). This driver
@@ -180,6 +194,7 @@ config USB_MXS_PHY
tristate "Freescale MXS USB PHY support"
depends on ARCH_MXC || ARCH_MXS
select STMP_DEVICE
+ select USB_PHY
help
Enable this to support the Freescale MXS USB PHY.
@@ -188,6 +203,7 @@ config USB_MXS_PHY
config USB_RCAR_PHY
tristate "Renesas R-Car USB PHY support"
depends on USB || USB_GADGET
+ select USB_PHY
help
Say Y here to add support for the Renesas R-Car USB common PHY driver.
This chip is typically used as USB PHY for USB host, gadget.
@@ -210,4 +226,4 @@ config USB_ULPI_VIEWPORT
Provides read/write operations to the ULPI phy register set for
controllers with a viewport register (e.g. Chipidea/ARC controllers).
-endif # USB_PHY
+endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 070eca3..dae321d 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -14,8 +14,10 @@ phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o
obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o
obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o
obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o
+obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o
obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o
+obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o
+obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o
obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o
diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h
new file mode 100644
index 0000000..b96594d
--- /dev/null
+++ b/drivers/usb/phy/am35x-phy-control.h
@@ -0,0 +1,21 @@
+#ifndef _AM335x_PHY_CONTROL_H_
+#define _AM335x_PHY_CONTROL_H_
+
+struct phy_control {
+ void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+ void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+ phy_ctrl->phy_power(phy_ctrl, id, on);
+}
+
+static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+ phy_ctrl->phy_wkup(phy_ctrl, id, on);
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev);
+
+#endif
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
new file mode 100644
index 0000000..22cf07d
--- /dev/null
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -0,0 +1,137 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct phy_control {
+ void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+ void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+struct am335x_control_usb {
+ struct device *dev;
+ void __iomem *phy_reg;
+ void __iomem *wkup;
+ spinlock_t lock;
+ struct phy_control phy_ctrl;
+};
+
+#define AM335X_USB0_CTRL 0x0
+#define AM335X_USB1_CTRL 0x8
+#define AM335x_USB_WKUP 0x0
+
+#define USBPHY_CM_PWRDN (1 << 0)
+#define USBPHY_OTG_PWRDN (1 << 1)
+#define USBPHY_OTGVDET_EN (1 << 19)
+#define USBPHY_OTGSESSEND_EN (1 << 20)
+
+static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+ struct am335x_control_usb *usb_ctrl;
+ u32 val;
+ u32 reg;
+
+ usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
+
+ switch (id) {
+ case 0:
+ reg = AM335X_USB0_CTRL;
+ break;
+ case 1:
+ reg = AM335X_USB1_CTRL;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ val = readl(usb_ctrl->phy_reg + reg);
+ if (on) {
+ val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+ val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+ } else {
+ val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
+ }
+
+ writel(val, usb_ctrl->phy_reg + reg);
+}
+
+static const struct phy_control ctrl_am335x = {
+ .phy_power = am335x_phy_power,
+};
+
+static const struct of_device_id omap_control_usb_id_table[] = {
+ { .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x },
+ {}
+};
+MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+
+static struct platform_driver am335x_control_driver;
+static int match(struct device *dev, void *data)
+{
+ struct device_node *node = (struct device_node *)data;
+ return dev->of_node == node &&
+ dev->driver == &am335x_control_driver.driver;
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev)
+{
+ struct device_node *node;
+ struct am335x_control_usb *ctrl_usb;
+
+ node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0);
+ if (!node)
+ return NULL;
+
+ dev = bus_find_device(&platform_bus_type, NULL, node, match);
+ ctrl_usb = dev_get_drvdata(dev);
+ if (!ctrl_usb)
+ return NULL;
+ return &ctrl_usb->phy_ctrl;
+}
+EXPORT_SYMBOL_GPL(am335x_get_phy_control);
+
+static int am335x_control_usb_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct am335x_control_usb *ctrl_usb;
+ const struct of_device_id *of_id;
+ const struct phy_control *phy_ctrl;
+
+ of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node);
+ if (!of_id)
+ return -EINVAL;
+
+ phy_ctrl = of_id->data;
+
+ ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL);
+ if (!ctrl_usb) {
+ dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+ return -ENOMEM;
+ }
+
+ ctrl_usb->dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+ ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctrl_usb->phy_reg))
+ return PTR_ERR(ctrl_usb->phy_reg);
+ spin_lock_init(&ctrl_usb->lock);
+ ctrl_usb->phy_ctrl = *phy_ctrl;
+
+ dev_set_drvdata(ctrl_usb->dev, ctrl_usb);
+ return 0;
+}
+
+static struct platform_driver am335x_control_driver = {
+ .probe = am335x_control_usb_probe,
+ .driver = {
+ .name = "am335x-control-usb",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(omap_control_usb_id_table),
+ },
+};
+
+module_platform_driver(am335x_control_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
new file mode 100644
index 0000000..c4d614d
--- /dev/null
+++ b/drivers/usb/phy/phy-am335x.c
@@ -0,0 +1,99 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "am35x-phy-control.h"
+#include "phy-generic.h"
+
+struct am335x_phy {
+ struct usb_phy_gen_xceiv usb_phy_gen;
+ struct phy_control *phy_ctrl;
+ int id;
+};
+
+static int am335x_init(struct usb_phy *phy)
+{
+ struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+ return 0;
+}
+
+static void am335x_shutdown(struct usb_phy *phy)
+{
+ struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+ phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+}
+
+static int am335x_phy_probe(struct platform_device *pdev)
+{
+ struct am335x_phy *am_phy;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL);
+ if (!am_phy)
+ return -ENOMEM;
+
+ am_phy->phy_ctrl = am335x_get_phy_control(dev);
+ if (!am_phy->phy_ctrl)
+ return -EPROBE_DEFER;
+ am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
+ if (am_phy->id < 0) {
+ dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
+ return am_phy->id;
+ }
+
+ ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen,
+ USB_PHY_TYPE_USB2, 0, false, false);
+ if (ret)
+ return ret;
+
+ ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
+ if (ret)
+ goto err_add;
+ am_phy->usb_phy_gen.phy.init = am335x_init;
+ am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
+
+ platform_set_drvdata(pdev, am_phy);
+ return 0;
+
+err_add:
+ usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen);
+ return ret;
+}
+
+static int am335x_phy_remove(struct platform_device *pdev)
+{
+ struct am335x_phy *am_phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&am_phy->usb_phy_gen.phy);
+ return 0;
+}
+
+static const struct of_device_id am335x_phy_ids[] = {
+ { .compatible = "ti,am335x-usb-phy" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, am335x_phy_ids);
+
+static struct platform_driver am335x_phy_driver = {
+ .probe = am335x_phy_probe,
+ .remove = am335x_phy_remove,
+ .driver = {
+ .name = "am335x-phy-driver",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(am335x_phy_ids),
+ },
+};
+
+module_platform_driver(am335x_phy_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
new file mode 100644
index 0000000..efe59f3
--- /dev/null
+++ b/drivers/usb/phy/phy-generic.c
@@ -0,0 +1,309 @@
+/*
+ * drivers/usb/otg/nop-usb-xceiv.c
+ *
+ * NOP USB transceiver for all USB transceiver which are either built-in
+ * into USB IP or which are mostly autonomous.
+ *
+ * Copyright (C) 2009 Texas Instruments Inc
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Current status:
+ * This provides a "nop" transceiver for PHYs which are
+ * autonomous such as isp1504, isp1707, etc.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+
+#include "phy-generic.h"
+
+static struct platform_device *pd;
+
+void usb_nop_xceiv_register(void)
+{
+ if (pd)
+ return;
+ pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0);
+ if (!pd) {
+ pr_err("Unable to register generic usb transceiver\n");
+ return;
+ }
+}
+EXPORT_SYMBOL(usb_nop_xceiv_register);
+
+void usb_nop_xceiv_unregister(void)
+{
+ platform_device_unregister(pd);
+ pd = NULL;
+}
+EXPORT_SYMBOL(usb_nop_xceiv_unregister);
+
+static int nop_set_suspend(struct usb_phy *x, int suspend)
+{
+ return 0;
+}
+
+int usb_gen_phy_init(struct usb_phy *phy)
+{
+ struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ if (!IS_ERR(nop->vcc)) {
+ if (regulator_enable(nop->vcc))
+ dev_err(phy->dev, "Failed to enable power\n");
+ }
+
+ if (!IS_ERR(nop->clk))
+ clk_enable(nop->clk);
+
+ if (!IS_ERR(nop->reset)) {
+ /* De-assert RESET */
+ if (regulator_enable(nop->reset))
+ dev_err(phy->dev, "Failed to de-assert reset\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gen_phy_init);
+
+void usb_gen_phy_shutdown(struct usb_phy *phy)
+{
+ struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ if (!IS_ERR(nop->reset)) {
+ /* Assert RESET */
+ if (regulator_disable(nop->reset))
+ dev_err(phy->dev, "Failed to assert reset\n");
+ }
+
+ if (!IS_ERR(nop->clk))
+ clk_disable(nop->clk);
+
+ if (!IS_ERR(nop->vcc)) {
+ if (regulator_disable(nop->vcc))
+ dev_err(phy->dev, "Failed to disable power\n");
+ }
+}
+EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown);
+
+static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
+{
+ if (!otg)
+ return -ENODEV;
+
+ if (!gadget) {
+ otg->gadget = NULL;
+ return -ENODEV;
+ }
+
+ otg->gadget = gadget;
+ otg->phy->state = OTG_STATE_B_IDLE;
+ return 0;
+}
+
+static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ if (!otg)
+ return -ENODEV;
+
+ if (!host) {
+ otg->host = NULL;
+ return -ENODEV;
+ }
+
+ otg->host = host;
+ return 0;
+}
+
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+ enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+ bool needs_reset)
+{
+ int err;
+
+ nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
+ GFP_KERNEL);
+ if (!nop->phy.otg)
+ return -ENOMEM;
+
+ nop->clk = devm_clk_get(dev, "main_clk");
+ if (IS_ERR(nop->clk)) {
+ dev_dbg(dev, "Can't get phy clock: %ld\n",
+ PTR_ERR(nop->clk));
+ }
+
+ if (!IS_ERR(nop->clk) && clk_rate) {
+ err = clk_set_rate(nop->clk, clk_rate);
+ if (err) {
+ dev_err(dev, "Error setting clock rate\n");
+ return err;
+ }
+ }
+
+ if (!IS_ERR(nop->clk)) {
+ err = clk_prepare(nop->clk);
+ if (err) {
+ dev_err(dev, "Error preparing clock\n");
+ return err;
+ }
+ }
+
+ nop->vcc = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(nop->vcc)) {
+ dev_dbg(dev, "Error getting vcc regulator: %ld\n",
+ PTR_ERR(nop->vcc));
+ if (needs_vcc)
+ return -EPROBE_DEFER;
+ }
+
+ nop->reset = devm_regulator_get(dev, "reset");
+ if (IS_ERR(nop->reset)) {
+ dev_dbg(dev, "Error getting reset regulator: %ld\n",
+ PTR_ERR(nop->reset));
+ if (needs_reset)
+ return -EPROBE_DEFER;
+ }
+
+ nop->dev = dev;
+ nop->phy.dev = nop->dev;
+ nop->phy.label = "nop-xceiv";
+ nop->phy.set_suspend = nop_set_suspend;
+ nop->phy.state = OTG_STATE_UNDEFINED;
+ nop->phy.type = type;
+
+ nop->phy.otg->phy = &nop->phy;
+ nop->phy.otg->set_host = nop_set_host;
+ nop->phy.otg->set_peripheral = nop_set_peripheral;
+
+ ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
+
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop)
+{
+ if (!IS_ERR(nop->clk))
+ clk_unprepare(nop->clk);
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy);
+
+static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_phy_gen_xceiv_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct usb_phy_gen_xceiv *nop;
+ enum usb_phy_type type = USB_PHY_TYPE_USB2;
+ int err;
+ u32 clk_rate = 0;
+ bool needs_vcc = false;
+ bool needs_reset = false;
+
+ if (dev->of_node) {
+ struct device_node *node = dev->of_node;
+
+ if (of_property_read_u32(node, "clock-frequency", &clk_rate))
+ clk_rate = 0;
+
+ needs_vcc = of_property_read_bool(node, "vcc-supply");
+ needs_reset = of_property_read_bool(node, "reset-supply");
+
+ } else if (pdata) {
+ type = pdata->type;
+ clk_rate = pdata->clk_rate;
+ needs_vcc = pdata->needs_vcc;
+ needs_reset = pdata->needs_reset;
+ }
+
+ nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
+ if (!nop)
+ return -ENOMEM;
+
+
+ err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc,
+ needs_reset);
+ if (err)
+ return err;
+
+ nop->phy.init = usb_gen_phy_init;
+ nop->phy.shutdown = usb_gen_phy_shutdown;
+
+ err = usb_add_phy_dev(&nop->phy);
+ if (err) {
+ dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
+ err);
+ goto err_add;
+ }
+
+ platform_set_drvdata(pdev, nop);
+
+ return 0;
+
+err_add:
+ usb_phy_gen_cleanup_phy(nop);
+ return err;
+}
+
+static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
+{
+ struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev);
+
+ usb_phy_gen_cleanup_phy(nop);
+ usb_remove_phy(&nop->phy);
+
+ return 0;
+}
+
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+ { .compatible = "usb-nop-xceiv" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
+
+static struct platform_driver usb_phy_gen_xceiv_driver = {
+ .probe = usb_phy_gen_xceiv_probe,
+ .remove = usb_phy_gen_xceiv_remove,
+ .driver = {
+ .name = "usb_phy_gen_xceiv",
+ .owner = THIS_MODULE,
+ .of_match_table = nop_xceiv_dt_ids,
+ },
+};
+
+static int __init usb_phy_gen_xceiv_init(void)
+{
+ return platform_driver_register(&usb_phy_gen_xceiv_driver);
+}
+subsys_initcall(usb_phy_gen_xceiv_init);
+
+static void __exit usb_phy_gen_xceiv_exit(void)
+{
+ platform_driver_unregister(&usb_phy_gen_xceiv_driver);
+}
+module_exit(usb_phy_gen_xceiv_exit);
+
+MODULE_ALIAS("platform:usb_phy_gen_xceiv");
+MODULE_AUTHOR("Texas Instruments Inc");
+MODULE_DESCRIPTION("NOP USB Transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
new file mode 100644
index 0000000..61687d5
--- /dev/null
+++ b/drivers/usb/phy/phy-generic.h
@@ -0,0 +1,20 @@
+#ifndef _PHY_GENERIC_H_
+#define _PHY_GENERIC_H_
+
+struct usb_phy_gen_xceiv {
+ struct usb_phy phy;
+ struct device *dev;
+ struct clk *clk;
+ struct regulator *vcc;
+ struct regulator *reset;
+};
+
+int usb_gen_phy_init(struct usb_phy *phy);
+void usb_gen_phy_shutdown(struct usb_phy *phy);
+
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+ enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+ bool needs_reset);
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop);
+
+#endif
diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c
deleted file mode 100644
index 55445e5d..0000000
--- a/drivers/usb/phy/phy-nop.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * drivers/usb/otg/nop-usb-xceiv.c
- *
- * NOP USB transceiver for all USB transceiver which are either built-in
- * into USB IP or which are mostly autonomous.
- *
- * Copyright (C) 2009 Texas Instruments Inc
- * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Current status:
- * This provides a "nop" transceiver for PHYs which are
- * autonomous such as isp1504, isp1707, etc.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/regulator/consumer.h>
-#include <linux/of.h>
-
-struct nop_usb_xceiv {
- struct usb_phy phy;
- struct device *dev;
- struct clk *clk;
- struct regulator *vcc;
- struct regulator *reset;
-};
-
-static struct platform_device *pd;
-
-void usb_nop_xceiv_register(void)
-{
- if (pd)
- return;
- pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
- if (!pd) {
- printk(KERN_ERR "Unable to register usb nop transceiver\n");
- return;
- }
-}
-EXPORT_SYMBOL(usb_nop_xceiv_register);
-
-void usb_nop_xceiv_unregister(void)
-{
- platform_device_unregister(pd);
- pd = NULL;
-}
-EXPORT_SYMBOL(usb_nop_xceiv_unregister);
-
-static int nop_set_suspend(struct usb_phy *x, int suspend)
-{
- return 0;
-}
-
-static int nop_init(struct usb_phy *phy)
-{
- struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
-
- if (!IS_ERR(nop->vcc)) {
- if (regulator_enable(nop->vcc))
- dev_err(phy->dev, "Failed to enable power\n");
- }
-
- if (!IS_ERR(nop->clk))
- clk_enable(nop->clk);
-
- if (!IS_ERR(nop->reset)) {
- /* De-assert RESET */
- if (regulator_enable(nop->reset))
- dev_err(phy->dev, "Failed to de-assert reset\n");
- }
-
- return 0;
-}
-
-static void nop_shutdown(struct usb_phy *phy)
-{
- struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
-
- if (!IS_ERR(nop->reset)) {
- /* Assert RESET */
- if (regulator_disable(nop->reset))
- dev_err(phy->dev, "Failed to assert reset\n");
- }
-
- if (!IS_ERR(nop->clk))
- clk_disable(nop->clk);
-
- if (!IS_ERR(nop->vcc)) {
- if (regulator_disable(nop->vcc))
- dev_err(phy->dev, "Failed to disable power\n");
- }
-}
-
-static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
-{
- if (!otg)
- return -ENODEV;
-
- if (!gadget) {
- otg->gadget = NULL;
- return -ENODEV;
- }
-
- otg->gadget = gadget;
- otg->phy->state = OTG_STATE_B_IDLE;
- return 0;
-}
-
-static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- if (!otg)
- return -ENODEV;
-
- if (!host) {
- otg->host = NULL;
- return -ENODEV;
- }
-
- otg->host = host;
- return 0;
-}
-
-static int nop_usb_xceiv_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
- struct nop_usb_xceiv *nop;
- enum usb_phy_type type = USB_PHY_TYPE_USB2;
- int err;
- u32 clk_rate = 0;
- bool needs_vcc = false;
- bool needs_reset = false;
-
- nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
- if (!nop)
- return -ENOMEM;
-
- nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
- GFP_KERNEL);
- if (!nop->phy.otg)
- return -ENOMEM;
-
- if (dev->of_node) {
- struct device_node *node = dev->of_node;
-
- if (of_property_read_u32(node, "clock-frequency", &clk_rate))
- clk_rate = 0;
-
- needs_vcc = of_property_read_bool(node, "vcc-supply");
- needs_reset = of_property_read_bool(node, "reset-supply");
-
- } else if (pdata) {
- type = pdata->type;
- clk_rate = pdata->clk_rate;
- needs_vcc = pdata->needs_vcc;
- needs_reset = pdata->needs_reset;
- }
-
- nop->clk = devm_clk_get(&pdev->dev, "main_clk");
- if (IS_ERR(nop->clk)) {
- dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
- PTR_ERR(nop->clk));
- }
-
- if (!IS_ERR(nop->clk) && clk_rate) {
- err = clk_set_rate(nop->clk, clk_rate);
- if (err) {
- dev_err(&pdev->dev, "Error setting clock rate\n");
- return err;
- }
- }
-
- if (!IS_ERR(nop->clk)) {
- err = clk_prepare(nop->clk);
- if (err) {
- dev_err(&pdev->dev, "Error preparing clock\n");
- return err;
- }
- }
-
- nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
- if (IS_ERR(nop->vcc)) {
- dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
- PTR_ERR(nop->vcc));
- if (needs_vcc)
- return -EPROBE_DEFER;
- }
-
- nop->reset = devm_regulator_get(&pdev->dev, "reset");
- if (IS_ERR(nop->reset)) {
- dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
- PTR_ERR(nop->reset));
- if (needs_reset)
- return -EPROBE_DEFER;
- }
-
- nop->dev = &pdev->dev;
- nop->phy.dev = nop->dev;
- nop->phy.label = "nop-xceiv";
- nop->phy.set_suspend = nop_set_suspend;
- nop->phy.init = nop_init;
- nop->phy.shutdown = nop_shutdown;
- nop->phy.state = OTG_STATE_UNDEFINED;
- nop->phy.type = type;
-
- nop->phy.otg->phy = &nop->phy;
- nop->phy.otg->set_host = nop_set_host;
- nop->phy.otg->set_peripheral = nop_set_peripheral;
-
- err = usb_add_phy_dev(&nop->phy);
- if (err) {
- dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
- err);
- goto err_add;
- }
-
- platform_set_drvdata(pdev, nop);
-
- ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
-
- return 0;
-
-err_add:
- if (!IS_ERR(nop->clk))
- clk_unprepare(nop->clk);
- return err;
-}
-
-static int nop_usb_xceiv_remove(struct platform_device *pdev)
-{
- struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
-
- if (!IS_ERR(nop->clk))
- clk_unprepare(nop->clk);
-
- usb_remove_phy(&nop->phy);
-
- return 0;
-}
-
-static const struct of_device_id nop_xceiv_dt_ids[] = {
- { .compatible = "usb-nop-xceiv" },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
-
-static struct platform_driver nop_usb_xceiv_driver = {
- .probe = nop_usb_xceiv_probe,
- .remove = nop_usb_xceiv_remove,
- .driver = {
- .name = "nop_usb_xceiv",
- .owner = THIS_MODULE,
- .of_match_table = nop_xceiv_dt_ids,
- },
-};
-
-static int __init nop_usb_xceiv_init(void)
-{
- return platform_driver_register(&nop_usb_xceiv_driver);
-}
-subsys_initcall(nop_usb_xceiv_init);
-
-static void __exit nop_usb_xceiv_exit(void)
-{
- platform_driver_unregister(&nop_usb_xceiv_driver);
-}
-module_exit(nop_usb_xceiv_exit);
-
-MODULE_ALIAS("platform:nop_usb_xceiv");
-MODULE_AUTHOR("Texas Instruments Inc");
-MODULE_DESCRIPTION("NOP USB Transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h
new file mode 100644
index 0000000..41f799f
--- /dev/null
+++ b/include/drm/i2c/tda998x.h
@@ -0,0 +1,23 @@
+#ifndef __TDA998X_H__
+#define __TDA998X_H__
+
+enum tda998x_audio_format {
+ AFMT_I2S,
+ AFMT_SPDIF,
+};
+
+struct tda998x_encoder_params {
+ int audio_cfg;
+ int audio_clk_cfg;
+ enum tda998x_audio_format audio_format;
+ int audio_sample_rate;
+ char audio_frame[6];
+ int swap_a, mirr_a;
+ int swap_b, mirr_b;
+ int swap_c, mirr_c;
+ int swap_d, mirr_d;
+ int swap_e, mirr_e;
+ int swap_f, mirr_f;
+};
+
+#endif
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index cb286b1..d71fe5d 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -370,6 +370,18 @@ struct dma_slave_config {
unsigned int slave_id;
};
+/* struct dma_slave_sg_limits - expose SG transfer limits of a channel
+ *
+ * @max_seg_nr: maximum number of SG segments supported on a SG/SLAVE
+ * channel (0 for no maximum or not a SG/SLAVE channel)
+ * @max_seg_len: maximum length of SG segments supported on a SG/SLAVE
+ * channel (0 for no maximum or not a SG/SLAVE channel)
+ */
+struct dma_slave_sg_limits {
+ u32 max_seg_nr;
+ u32 max_seg_len;
+};
+
static inline const char *dma_chan_name(struct dma_chan *chan)
{
return dev_name(&chan->dev->device);
@@ -532,6 +544,7 @@ struct dma_tx_state {
* struct with auxiliary transfer status information, otherwise the call
* will just return a simple status code
* @device_issue_pending: push pending transactions to hardware
+ * @device_slave_sg_limits: return the slave SG capabilities
*/
struct dma_device {
@@ -597,6 +610,9 @@ struct dma_device {
dma_cookie_t cookie,
struct dma_tx_state *txstate);
void (*device_issue_pending)(struct dma_chan *chan);
+ struct dma_slave_sg_limits *(*device_slave_sg_limits)(
+ struct dma_chan *chan, enum dma_slave_buswidth addr_width,
+ u32 maxburst);
};
static inline int dmaengine_device_control(struct dma_chan *chan,
@@ -958,6 +974,29 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
}
}
+/**
+ * dma_get_slave_sg_limits - get DMAC SG transfer capabilities
+ * @chan: target DMA channel
+ * @addr_width: address width of the DMA transfer
+ * @maxburst: maximum DMA transfer burst size
+ *
+ * Get SG transfer capabilities for a specified channel. If the dmaengine
+ * driver does not implement SG transfer capabilities then NULL is
+ * returned.
+ */
+static inline struct dma_slave_sg_limits
+*dma_get_slave_sg_limits(struct dma_chan *chan,
+ enum dma_slave_buswidth addr_width,
+ u32 maxburst)
+{
+ if (chan->device->device_slave_sg_limits)
+ return chan->device->device_slave_sg_limits(chan,
+ addr_width,
+ maxburst);
+
+ return NULL;
+}
+
enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
#ifdef CONFIG_DMA_ENGINE
enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
diff --git a/include/linux/i2c/eeprom.h b/include/linux/i2c/eeprom.h
new file mode 100644
index 0000000..1393980
--- /dev/null
+++ b/include/linux/i2c/eeprom.h
@@ -0,0 +1,59 @@
+/*
+ * i2c/eeprom.h
+ *
+ * In-kernel interface for accessing eeprom memory.
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Pantelis Antoniou <panto@antoniou-consulting.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.
+ */
+#ifndef I2C_EEPROM_H
+#define I2C_EEPROM_H
+
+#include <linux/types.h>
+#include <linux/memory.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+
+/*
+ * The method called in the client is
+ *
+ * int command(struct i2c_client *client, unsigned int cmd, void *arg);
+ *
+ * A single command is supported, which returns a pointer to the memory
+ * accessor already available, but which was only accessible via platform
+ * callbacks. We can't use platform callbacks anymore for device tree
+ * platforms, hence this interface.
+ *
+ */
+
+/* interface commands */
+#define I2C_EEPROM_GET_MEMORY_ACCESSOR 1
+
+static inline struct memory_accessor *
+i2c_eeprom_get_memory_accessor(struct i2c_client *client)
+{
+ int ret;
+ struct memory_accessor *macc;
+
+ /* verify that the i2c client's driver has a command method */
+ if (!client || !client->driver || !client->driver->command)
+ return ERR_PTR(-ENOTSUPP);
+
+ macc = NULL;
+ ret = client->driver->command(client, I2C_EEPROM_GET_MEMORY_ACCESSOR,
+ &macc);
+ if (ret != 0)
+ return ERR_PTR(ret);
+
+ if (macc == NULL)
+ return ERR_PTR(-ENOTSUPP);
+
+ return macc;
+}
+
+#endif
diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h
index cfb545c..53fca8f 100644
--- a/include/linux/of_i2c.h
+++ b/include/linux/of_i2c.h
@@ -15,6 +15,9 @@
#if defined(CONFIG_OF_I2C) || defined(CONFIG_OF_I2C_MODULE)
#include <linux/i2c.h>
+struct i2c_client *
+of_i2c_register_device(struct i2c_adapter *adap, struct device_node *node);
+
extern void of_i2c_register_devices(struct i2c_adapter *adap);
/* must call put_device() when done with returned i2c_client device */
@@ -25,6 +28,14 @@ extern struct i2c_adapter *of_find_i2c_adapter_by_node(
struct device_node *node);
#else
+
+static inline struct i2c_client *
+of_i2c_register_device(struct i2c_adapter *adap,
+ struct device_node *node)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline void of_i2c_register_devices(struct i2c_adapter *adap)
{
return;
diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h
index 2bf1b30..d548994 100644
--- a/include/linux/platform_data/mmc-omap.h
+++ b/include/linux/platform_data/mmc-omap.h
@@ -115,6 +115,9 @@ struct omap_mmc_platform_data {
int switch_pin; /* gpio (card detect) */
int gpio_wp; /* gpio (write protect) */
+ int gpio_reset; /* gpio (reset) */
+ int gpio_reset_active_low; /* 1 if reset is active low */
+ u32 gpio_reset_hold_us; /* time to hold in us */
int (*set_bus_mode)(struct device *dev, int slot, int bus_mode);
int (*set_power)(struct device *dev, int slot,
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index ce8e4ff..fb3dbce 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -325,4 +325,8 @@ extern int platform_pm_restore(struct device *dev);
#define USE_PLATFORM_PM_SLEEP_OPS
#endif
+/* helper functions for resource list managment */
+int platform_device_unlink_resources(struct platform_device *pdev);
+int platform_device_link_resources(struct platform_device *pdev);
+
#endif /* _PLATFORM_DEVICE_H_ */
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h
deleted file mode 100644
index 148d351..0000000
--- a/include/linux/usb/nop-usb-xceiv.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __LINUX_USB_NOP_XCEIV_H
-#define __LINUX_USB_NOP_XCEIV_H
-
-#include <linux/usb/otg.h>
-
-struct nop_usb_xceiv_platform_data {
- enum usb_phy_type type;
- unsigned long clk_rate;
-
- /* if set fails with -EPROBE_DEFER if can't get regulator */
- unsigned int needs_vcc:1;
- unsigned int needs_reset:1;
-};
-
-#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
-/* sometimes transceivers are accessed only through e.g. ULPI */
-extern void usb_nop_xceiv_register(void);
-extern void usb_nop_xceiv_unregister(void);
-#else
-static inline void usb_nop_xceiv_register(void)
-{
-}
-
-static inline void usb_nop_xceiv_unregister(void)
-{
-}
-#endif
-
-#endif /* __LINUX_USB_NOP_XCEIV_H */
diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h
new file mode 100644
index 0000000..f9a7e7b
--- /dev/null
+++ b/include/linux/usb/usb_phy_gen_xceiv.h
@@ -0,0 +1,29 @@
+#ifndef __LINUX_USB_NOP_XCEIV_H
+#define __LINUX_USB_NOP_XCEIV_H
+
+#include <linux/usb/otg.h>
+
+struct usb_phy_gen_xceiv_platform_data {
+ enum usb_phy_type type;
+ unsigned long clk_rate;
+
+ /* if set fails with -EPROBE_DEFER if can't get regulator */
+ unsigned int needs_vcc:1;
+ unsigned int needs_reset:1;
+};
+
+#if IS_ENABLED(CONFIG_NOP_USB_XCEIV)
+/* sometimes transceivers are accessed only through e.g. ULPI */
+extern void usb_nop_xceiv_register(void);
+extern void usb_nop_xceiv_unregister(void);
+#else
+static inline void usb_nop_xceiv_register(void)
+{
+}
+
+static inline void usb_nop_xceiv_unregister(void)
+{
+}
+#endif
+
+#endif /* __LINUX_USB_NOP_XCEIV_H */
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index aa924d9..461fe4f 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -276,6 +276,16 @@ struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
+struct dma_chan *snd_dmaengine_pcm_request_slave_channel(
+ struct snd_pcm_substream *substream, char *name)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ return dma_request_slave_channel(dev, name);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_slave_channel);
+
/**
* snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
* @substream: PCM substream
@@ -334,6 +344,18 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
+int snd_dmaengine_pcm_open_request_slave_chan(struct snd_pcm_substream *substream, char *name)
+{
+ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ return snd_dmaengine_pcm_open(substream,
+ snd_dmaengine_pcm_request_slave_channel(substream, "tx"));
+ } else {
+ return snd_dmaengine_pcm_open(substream,
+ snd_dmaengine_pcm_request_slave_channel(substream, "rx"));
+ }
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_slave_chan);
+
/**
* snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
* @substream: PCM substream