* [PATCH v6 0/2] Introduce AEMIF driver for Davinci/Keystone archs
From: Ivan Khoronzhuk @ 2014-02-24 17:26 UTC (permalink / raw)
To: gregkh, santosh.shilimkar, galak
Cc: mark.rutland, devicetree, grygorii.strashko, linux, pawel.moll,
swarren, ijc+devicetree, nsekhar, linux-kernel, rob.herring,
robherring2, rob, Ivan Khoronzhuk, linux-mtd, dwmw2,
linux-arm-kernel
These patches introduce Async External Memory Interface (EMIF16/AEMIF)
controller driver for Davinci/Keystone archs.
For more informations see documentation:
Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
OMAP-L138 - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf
Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
Based on v3.14-rc4
v5..v6:
- memory: ti-aemif: introduce AEMIF driver
- memory: ti-aemif: add bindings for AEMIF driver
changed opaque names for cs node properties
v4..v5:
- memory: ti-aemif: introduce AEMIF driver
deleted DRV_NAME in favour of KBUILD_MODNAME
deleted redundant err message in case of memory allocation
some cosmetic changes
v3..v4:
rebased on latest of linux-keystone.git keystone/master
v2..v3 (https://lkml.org/lkml/2013/12/11/148):
- memory: ti-aemif: introduce AEMIF driver
changed to work with multiple AEMIF controllers
corrected "copyright" to "authors" in header
changed compatible "ti,omap-L138-aemif" to "ti,da850-aeimf"
used NULL in clk_get() instead of "aemif" name
driver can be build as loadable module
treat all child nodes as cs nodes, it makes code simpler
- memory: ti-aemif: add bindings for AEMIF driver
deleted direct link driver/memory/ti-aemif.c
clarified description of controller ranges property
changed compatible "ti,omap-L138-aemif" to "ti,da850-aeimf"
added cs number information in commit log
removed compatible property from cs node, it makes code simpler
v1..v2 (https://lkml.org/lkml/2013/11/21/170):
- memory: ti-aemif: introduce AEMIF driver
- memory: ti-aemif: add bindings for AEMIF driver
added ti.cs-chipselect property instead of representing chipselect
number in cs node name.
Ivan Khoronzhuk (2):
memory: ti-aemif: introduce AEMIF driver
memory: ti-aemif: add bindings for AEMIF driver
.../bindings/memory-controllers/ti-aemif.txt | 210 ++++++++++
drivers/memory/Kconfig | 11 +
drivers/memory/Makefile | 1 +
drivers/memory/ti-aemif.c | 427 +++++++++++++++++++++
4 files changed, 649 insertions(+)
create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt
create mode 100644 drivers/memory/ti-aemif.c
--
1.8.3.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply
* [PATCH 2/2] ARM: dts: duovero-parlor: Add HDMI output
From: Florian Vaussard @ 2014-02-24 17:07 UTC (permalink / raw)
To: Benoît Cousson, Tony Lindgren
Cc: devicetree, linux-arm-kernel, linux-omap, Ash Charles,
Florian Vaussard
In-Reply-To: <1393261669-32039-1-git-send-email-florian.vaussard@epfl.ch>
Add the necessary DTS nodes to enable the micro-HDMI output on Parlor
board.
Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
---
arch/arm/boot/dts/omap4-duovero-parlor.dts | 36 ++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/arch/arm/boot/dts/omap4-duovero-parlor.dts b/arch/arm/boot/dts/omap4-duovero-parlor.dts
index 96f51d8..d038242 100644
--- a/arch/arm/boot/dts/omap4-duovero-parlor.dts
+++ b/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -15,6 +15,10 @@
model = "OMAP4430 Gumstix Duovero on Parlor";
compatible = "gumstix,omap4-duovero-parlor", "gumstix,omap4-duovero", "ti,omap4430", "ti,omap4";
+ aliases {
+ display0 = &hdmi0;
+ };
+
leds {
compatible = "gpio-leds";
led0 {
@@ -35,6 +39,15 @@
gpio-key,wakeup;
};
};
+
+ hdmi0: connector@0 {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
};
&omap4_pmx_core {
@@ -77,6 +90,15 @@
0x30 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a24.gpio_48: amdix enabled */
>;
};
+
+ dss_hdmi_pins: pinmux_dss_hdmi_pins {
+ pinctrl-single,pins = <
+ 0x58 (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_hpd.hdmi_hpd */
+ 0x5a (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ 0x5c (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_ddc_scl.hdmi_ddc_scl */
+ 0x5e (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_ddc_sda.hdmi_ddc_sda */
+ >;
+ };
};
&i2c2 {
@@ -143,4 +165,18 @@
};
};
+&dss {
+ status = "ok";
+};
+
+&hdmi {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&dss_hdmi_pins>;
+
+ hdmi_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+};
--
1.8.1.2
^ permalink raw reply related
* [PATCH 1/2] ARM: dts: Add support for OMAP4 Gumstix DuoVero/Parlor
From: Florian Vaussard @ 2014-02-24 17:07 UTC (permalink / raw)
To: Benoît Cousson, Tony Lindgren
Cc: devicetree, linux-arm-kernel, linux-omap, Ash Charles,
Florian Vaussard
In-Reply-To: <1393261669-32039-1-git-send-email-florian.vaussard@epfl.ch>
Gumstix DuoVero is an OMAP4430-based Computer On Module.
Parlor is one of the available expansion board.
Tested features:
- GPMC ethernet
- HSUSB2 and OTG
- Audio out
- WiFi and Bluetooth (w2cbw0015 SDIO module)
- LED and button
Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
---
.../devicetree/bindings/arm/omap/omap.txt | 3 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/omap4-duovero-parlor.dts | 146 ++++++++++++
arch/arm/boot/dts/omap4-duovero.dtsi | 252 +++++++++++++++++++++
4 files changed, 402 insertions(+)
create mode 100644 arch/arm/boot/dts/omap4-duovero-parlor.dts
create mode 100644 arch/arm/boot/dts/omap4-duovero.dtsi
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index af9b4a0..95b1372 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -99,6 +99,9 @@ Boards:
- OMAP4 PandaBoard : Low cost community board
compatible = "ti,omap4-panda", "ti,omap4430"
+- OMAP4 DuoVero with Parlor : Commercial expansion board with daughter board
+ compatible = "gumstix,omap4-duovero-parlor", "gumstix,omap4-duovero", "ti,omap4430", "ti,omap4";
+
- OMAP3 EVM : Software Development Board for OMAP35x, AM/DM37x
compatible = "ti,omap3-evm", "ti,omap3"
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 0320303..8b23abb 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -215,6 +215,7 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap3-igep0020.dtb \
omap3-igep0030.dtb \
omap3-zoom3.dtb \
+ omap4-duovero-parlor.dtb \
omap4-panda.dtb \
omap4-panda-a4.dtb \
omap4-panda-es.dtb \
diff --git a/arch/arm/boot/dts/omap4-duovero-parlor.dts b/arch/arm/boot/dts/omap4-duovero-parlor.dts
new file mode 100644
index 0000000..96f51d8
--- /dev/null
+++ b/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group
+ *
+ * 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 "omap4-duovero.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "OMAP4430 Gumstix Duovero on Parlor";
+ compatible = "gumstix,omap4-duovero-parlor", "gumstix,omap4-duovero", "ti,omap4430", "ti,omap4";
+
+ leds {
+ compatible = "gpio-leds";
+ led0 {
+ label = "duovero:blue:led0";
+ gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; /* gpio_122 */
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ button0@121 {
+ label = "button0";
+ linux,code = <BTN_0>;
+ gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; /* gpio_121 */
+ gpio-key,wakeup;
+ };
+ };
+};
+
+&omap4_pmx_core {
+ pinctrl-0 = <
+ &led_pins
+ &button_pins
+ &smsc_pins
+ >;
+
+ led_pins: pinmux_led_pins {
+ pinctrl-single,pins = <
+ 0xd6 (PIN_OUTPUT | MUX_MODE3) /* abe_dmic_din3.gpio_122 */
+ >;
+ };
+
+ button_pins: pinmux_button_pins {
+ pinctrl-single,pins = <
+ 0xd4 (PIN_INPUT_PULLUP | MUX_MODE3) /* abe_dmic_din2.gpio_121 */
+ >;
+ };
+
+ i2c2_pins: pinmux_i2c2_pins {
+ pinctrl-single,pins = <
+ 0xe6 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_scl */
+ 0xe8 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c2_sda */
+ >;
+ };
+
+ i2c3_pins: pinmux_i2c3_pins {
+ pinctrl-single,pins = <
+ 0xea (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_scl */
+ 0xec (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */
+ >;
+ };
+
+ smsc_pins: pinmux_smsc_pins {
+ pinctrl-single,pins = <
+ 0x28 (PIN_INPUT | MUX_MODE3) /* gpmc_a20.gpio_44: IRQ */
+ 0x2a (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a21.gpio_45: nReset */
+ 0x30 (PIN_INPUT_PULLUP | MUX_MODE3) /* gpmc_a24.gpio_48: amdix enabled */
+ >;
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins>;
+
+ clock-frequency = <100000>;
+
+ /* optional 1K EEPROM with revision information */
+ eeprom@51 {
+ compatible = "atmel,24c01";
+ reg = <0x51>;
+ pagesize = <8>;
+ };
+};
+
+&mmc3 {
+ status = "disabled";
+};
+
+#include "omap-gpmc-smsc911x.dtsi"
+
+&gpmc {
+ ranges = <5 0 0x2c000000 0x1000000>; /* CS5 */
+
+ ethernet@gpmc {
+ reg = <5 0 0xff>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <12 IRQ_TYPE_LEVEL_LOW>; /* gpio_44 */
+
+ phy-mode = "mii";
+
+ gpmc,cs-on-ns = <10>;
+ gpmc,cs-rd-off-ns = <50>;
+ gpmc,cs-wr-off-ns = <50>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <10>;
+ gpmc,adv-wr-off-ns = <10>;
+ gpmc,oe-on-ns = <15>;
+ gpmc,oe-off-ns = <50>;
+ gpmc,we-on-ns = <15>;
+ gpmc,we-off-ns = <50>;
+ gpmc,rd-cycle-ns = <50>;
+ gpmc,wr-cycle-ns = <50>;
+ gpmc,access-ns = <50>;
+ gpmc,page-burst-access-ns = <0>;
+ gpmc,bus-turnaround-ns = <35>;
+ gpmc,cycle2cycle-delay-ns = <35>;
+ gpmc,wr-data-mux-bus-ns = <35>;
+ gpmc,wr-access-ns = <50>;
+
+ gpmc,mux-add-data = <2>;
+ gpmc,sync-read;
+ gpmc,sync-write;
+ gpmc,clk-activation-ns = <5>;
+ gpmc,sync-clk-ps = <20000>;
+ };
+};
+
+
diff --git a/arch/arm/boot/dts/omap4-duovero.dtsi b/arch/arm/boot/dts/omap4-duovero.dtsi
new file mode 100644
index 0000000..a514791
--- /dev/null
+++ b/arch/arm/boot/dts/omap4-duovero.dtsi
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2014 Florian Vaussard, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "omap443x.dtsi"
+
+/ {
+ model = "Gumstix Duovero";
+ compatible = "gumstix,omap4-duovero", "ti,omap4430", "ti,omap4";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>; /* 1 GB */
+ };
+
+ sound {
+ compatible = "ti,abe-twl6040";
+ ti,model = "DuoVero";
+
+ ti,mclk-freq = <38400000>;
+
+ ti,mcpdm = <&mcpdm>;
+
+ ti,twl6040 = <&twl6040>;
+
+ /* Audio routing */
+ ti,audio-routing =
+ "Headset Stereophone", "HSOL",
+ "Headset Stereophone", "HSOR",
+ "HSMIC", "Headset Mic",
+ "Headset Mic", "Headset Mic Bias";
+ };
+
+ /* HS USB Host PHY on PORT 1 */
+ hsusb1_phy: hsusb1_phy {
+ compatible = "usb-nop-xceiv";
+ reset-gpios = <&gpio2 30 GPIO_ACTIVE_LOW>; /* gpio_62 */
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hsusb1phy_pins>;
+
+ clocks = <&auxclk3_ck>;
+ clock-names = "main_clk";
+ clock-frequency = <19200000>;
+ };
+
+ /* regulator for w2cbw0015 on sdio5 */
+ w2cbw0015_vmmc: w2cbw0015_vmmc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&w2cbw0015_pins>;
+ compatible = "regulator-fixed";
+ regulator-name = "w2cbw0015";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ gpio = <&gpio2 11 GPIO_ACTIVE_LOW>; /* gpio_43 */
+ startup-delay-us = <70000>;
+ enable-active-high;
+ regulator-boot-on;
+ };
+};
+
+&omap4_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &twl6040_pins
+ &mcpdm_pins
+ &mcbsp1_pins
+ &hsusbb1_pins
+ >;
+
+ twl6040_pins: pinmux_twl6040_pins {
+ pinctrl-single,pins = <
+ 0x126 (PIN_OUTPUT | MUX_MODE3) /* usbb2_ulpitll_nxt.gpio_160 */
+ 0x160 (PIN_INPUT | MUX_MODE0) /* sys_nirq2.sys_nirq2 */
+ >;
+ };
+
+ mcpdm_pins: pinmux_mcpdm_pins {
+ pinctrl-single,pins = <
+ 0xc6 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_ul_data.abe_pdm_ul_data */
+ 0xc8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_dl_data.abe_pdm_dl_data */
+ 0xca (PIN_INPUT_PULLUP | MUX_MODE0) /* abe_pdm_frame.abe_pdm_frame */
+ 0xcc (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_pdm_lb_clk.abe_pdm_lb_clk */
+ 0xce (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
+ >;
+ };
+
+ mcbsp1_pins: pinmux_mcbsp1_pins {
+ pinctrl-single,pins = <
+ 0xbe (PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_clkx.abe_mcbsp1_clkx */
+ 0xc0 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dr.abe_mcbsp1_dr */
+ 0xc2 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abe_mcbsp1_dx.abe_mcbsp1_dx */
+ 0xc4 (PIN_INPUT | MUX_MODE0) /* abe_mcbsp1_fsx.abe_mcbsp1_fsx */
+ >;
+ };
+
+ hsusbb1_pins: pinmux_hsusbb1_pins {
+ pinctrl-single,pins = <
+ 0x82 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_clk.usbb1_ulpiphy_clk */
+ 0x84 (PIN_OUTPUT | MUX_MODE4) /* usbb1_ulpitll_stp.usbb1_ulpiphy_stp */
+ 0x86 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dir.usbb1_ulpiphy_dir */
+ 0x88 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_nxt.usbb1_ulpiphy_nxt */
+ 0x8a (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat0.usbb1_ulpiphy_dat0 */
+ 0x8c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat1.usbb1_ulpiphy_dat1 */
+ 0x8e (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat2.usbb1_ulpiphy_dat2 */
+ 0x90 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat3.usbb1_ulpiphy_dat3 */
+ 0x92 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat4.usbb1_ulpiphy_dat4 */
+ 0x94 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat5.usbb1_ulpiphy_dat5 */
+ 0x96 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat6.usbb1_ulpiphy_dat6 */
+ 0x98 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* usbb1_ulpitll_dat7.usbb1_ulpiphy_dat7 */
+ >;
+ };
+
+ hsusb1phy_pins: pinmux_hsusb1phy_pins {
+ pinctrl-single,pins = <
+ 0x4c (PIN_OUTPUT | MUX_MODE3) /* gpmc_wait1.gpio_62 */
+ >;
+ };
+
+ w2cbw0015_pins: pinmux_w2cbw0015_pins {
+ pinctrl-single,pins = <
+ 0x26 (PIN_OUTPUT | MUX_MODE3) /* gpmc_a19.gpio_43 */
+ 0x3a (PIN_INPUT | MUX_MODE3) /* gpmc_ncs3.gpio_53 */
+ >;
+ };
+
+ i2c1_pins: pinmux_i2c1_pins {
+ pinctrl-single,pins = <
+ 0xe2 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ 0xe4 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ >;
+ };
+
+ i2c4_pins: pinmux_i2c4_pins {
+ pinctrl-single,pins = <
+ 0xee (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_scl */
+ 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c4_sda */
+ >;
+ };
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ 0xa2 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk */
+ 0xa4 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmcc1_cmd */
+ 0xa6 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmcc1_dat0 */
+ 0xa8 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1 */
+ 0xaa (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2 */
+ 0xac (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3 */
+ >;
+ };
+
+ mmc5_pins: pinmux_mmc5_pins {
+ pinctrl-single,pins = <
+ 0x108 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_clk */
+ 0x10a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmcc5_cmd */
+ 0x10c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmcc5_dat0 */
+ 0x10e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat1 */
+ 0x110 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat2 */
+ 0x112 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc5_dat3 */
+ >;
+ };
+};
+
+/* PMIC */
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
+ clock-frequency = <400000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_1N cascaded to gic */
+ interrupt-parent = <&gic>;
+ };
+
+ twl6040: twl@4b {
+ compatible = "ti,twl6040";
+ reg = <0x4b>;
+ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
+ interrupt-parent = <&gic>;
+ ti,audpwron-gpio = <&gpio6 0 GPIO_ACTIVE_HIGH>; /* gpio_160 */
+
+ vio-supply = <&v1v8>;
+ v2v1-supply = <&v2v1>;
+ enable-active-high;
+ };
+};
+
+#include "twl6030.dtsi"
+#include "twl6030_omap4.dtsi"
+
+/* on-board bluetooth / WiFi module */
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins>;
+
+ clock-frequency = <400000>;
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+
+ vmmc-supply = <&vmmc>;
+ ti,bus-width = <4>;
+ ti,non-removable; /* FIXME: use PMIC_MMC detect */
+};
+
+&mmc2 {
+ status = "disabled";
+};
+
+/* mmc3 is available to the expansion board */
+
+&mmc4 {
+ status = "disabled";
+};
+
+/* on-board WiFi module */
+&mmc5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc5_pins>;
+
+ vmmc-supply = <&w2cbw0015_vmmc>;
+ ti,bus-width = <4>;
+ ti,non-removable;
+ cap-power-off-card;
+};
+
+&twl_usb_comparator {
+ usb-supply = <&vusb>;
+};
+
+&usb_otg_hs {
+ interface-type = <1>;
+ mode = <3>;
+ power = <50>;
+};
+
+&usbhshost {
+ port1-mode = "ehci-phy";
+};
+
+&usbhsehci {
+ phys = <&hsusb1_phy>;
+};
+
--
1.8.1.2
^ permalink raw reply related
* [PATCH 0/2] ARM: dts: OMAP4: Add support for DuoVero/Parlor
From: Florian Vaussard @ 2014-02-24 17:07 UTC (permalink / raw)
To: Benoît Cousson, Tony Lindgren
Cc: devicetree, linux-arm-kernel, linux-omap, Ash Charles,
Florian Vaussard
Hi Benoit, Tony,
Here is a device tree to support the OMAP4430-based Gumstix DuoVero
with the Parlor expansion boards. All peripherals should be working
with current 3.14-rc4, except:
- GPMC ethernet (needs patches [1])
- TWL6040 init may fail (will send a bug report to ML)
- The HDMI output depends on Tomi's DSS series [2] (not yet merged)
I split the HDMI part into a second patch, so it can be merged with the DSS
series, even if the nodes could be merged independently.
Regards,
Florian
[1] http://thread.gmane.org/gmane.linux.ports.arm.omap/110662
[2] http://thread.gmane.org/gmane.linux.ports.arm.kernel/295881
Florian Vaussard (2):
ARM: dts: Add support for OMAP4 Gumstix DuoVero/Parlor
ARM: dts: duovero-parlor: Add HDMI output
.../devicetree/bindings/arm/omap/omap.txt | 3 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/omap4-duovero-parlor.dts | 182 +++++++++++++++
arch/arm/boot/dts/omap4-duovero.dtsi | 252 +++++++++++++++++++++
4 files changed, 438 insertions(+)
create mode 100644 arch/arm/boot/dts/omap4-duovero-parlor.dts
create mode 100644 arch/arm/boot/dts/omap4-duovero.dtsi
--
1.8.1.2
^ permalink raw reply
* Re: [RFC PATCH v3 1/9] staging: imx-drm-core: don't request probe deferral in imx_drm_encoder_parse_of
From: Russell King - ARM Linux @ 2014-02-24 17:06 UTC (permalink / raw)
To: Philipp Zabel
Cc: devel, devicetree, Greg Kroah-Hartman, dri-devel, kernel,
Grant Likely, linux-arm-kernel
In-Reply-To: <1393260998.3091.63.camel@pizza.hi.pengutronix.de>
On Mon, Feb 24, 2014 at 05:56:38PM +0100, Philipp Zabel wrote:
> Am Montag, den 24.02.2014, 15:49 +0000 schrieb Russell King - ARM Linux:
> One issue was that the DT parsing code would try to add the imx-ldb
> component right after the first crtc, and then its bind would fail
> in imx_drm_encoder_parse_of because the three remaining crtcs were
> not yet registered. This is already fixed by adding the crtc
> components first.
That's what happens anyway - we add /all/ the CRTCs first before we
start adding the connectors.
That means the CRTCs will be bound before the connectors (ldb).
What you're probably missing is that with what's in my branch, if you
want both CRTCs or the second CRTC in the IPU pair, you must specify
both in the "crtcs" property - iow "crtcs = <&ipuX 0>, <&ipuX 1>".
The reason is there's no way to differentiate the individual platform
devices there without delving into the platform data.
--
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
^ permalink raw reply
* Re: [RFC PATCH v3 1/9] staging: imx-drm-core: don't request probe deferral in imx_drm_encoder_parse_of
From: Philipp Zabel @ 2014-02-24 17:03 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: devel, devicetree, David Airlie, Greg Kroah-Hartman, dri-devel,
kernel, Grant Likely, Shawn Guo, linux-arm-kernel, Lucas Stach
In-Reply-To: <1393260998.3091.63.camel@pizza.hi.pengutronix.de>
Am Montag, den 24.02.2014, 17:56 +0100 schrieb Philipp Zabel:
> Am Montag, den 24.02.2014, 15:49 +0000 schrieb Russell King - ARM Linux:
> > On Tue, Feb 18, 2014 at 12:36:02PM +0100, Philipp Zabel wrote:
> > > From: Lucas Stach <l.stach@pengutronix.de>
> > >
> > > Since imx_drm_encoder_parse_of is called from the encoder bind callbacks,
> > > it is too late to request probe deferral. Rather the core should make sure
> > > that the crtcs are bound before the encoders, after all needed components
> > > are probed.
> >
> > Why is it too late? -EPROBE_DEFER from this point will cause the driver
> > initialisation to correctly unwind and return -EPROBE_DEFER to the
> > last-to-be-added component.
>
> Hmm, you are right. I have conflated two separate issues here. I'll back
> that out.
>
> > > This fixes probe failure when using the LDB on i.MX6.
> >
> > More details please.
>
> One issue was that the DT parsing code would try to add the imx-ldb
> component right after the first crtc, and then its bind would fail
> in imx_drm_encoder_parse_of because the three remaining crtcs were
> not yet registered. This is already fixed by adding the crtc
> components first.
On second thought, now that the crtcs are all bound before the encoders,
we'll never even reach this point until all crtcs are available.
regards
Philipp
^ permalink raw reply
* Re: [RFC PATCH v3 1/9] staging: imx-drm-core: don't request probe deferral in imx_drm_encoder_parse_of
From: Philipp Zabel @ 2014-02-24 16:56 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: devel, devicetree, David Airlie, Greg Kroah-Hartman, dri-devel,
kernel, Grant Likely, Shawn Guo, linux-arm-kernel, Lucas Stach
In-Reply-To: <20140224154919.GL21483@n2100.arm.linux.org.uk>
Am Montag, den 24.02.2014, 15:49 +0000 schrieb Russell King - ARM Linux:
> On Tue, Feb 18, 2014 at 12:36:02PM +0100, Philipp Zabel wrote:
> > From: Lucas Stach <l.stach@pengutronix.de>
> >
> > Since imx_drm_encoder_parse_of is called from the encoder bind callbacks,
> > it is too late to request probe deferral. Rather the core should make sure
> > that the crtcs are bound before the encoders, after all needed components
> > are probed.
>
> Why is it too late? -EPROBE_DEFER from this point will cause the driver
> initialisation to correctly unwind and return -EPROBE_DEFER to the
> last-to-be-added component.
Hmm, you are right. I have conflated two separate issues here. I'll back
that out.
> > This fixes probe failure when using the LDB on i.MX6.
>
> More details please.
One issue was that the DT parsing code would try to add the imx-ldb
component right after the first crtc, and then its bind would fail
in imx_drm_encoder_parse_of because the three remaining crtcs were
not yet registered. This is already fixed by adding the crtc
components first.
The other issue is that once we add bridges that also have output
ports, imx_drm_encoder_parse_of needs to skip those.
thanks
Philipp
^ permalink raw reply
* Re: [PATCH] ASoC: cs42888: Add codec driver support
From: Austin, Brian @ 2014-02-24 16:32 UTC (permalink / raw)
To: Nicolin Chen
Cc: Mark Brown, Handrigan, Paul,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
pawel.moll-5wv7dgnIgG8@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org,
galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org, Liam Girdwood,
grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org
In-Reply-To: <20140224160648.GC6132@MrMyself>
[-- Attachment #1: Type: text/plain, Size: 1451 bytes --]
On Feb 24, 2014, at 10:06 AM, Nicolin Chen <Guangyu.Chen-KZfg59tc24xl57MIdRCFDg@public.gmane.org> wrote:
> On Mon, Feb 24, 2014 at 03:52:24PM +0000, Austin, Brian wrote:
>>>> + if (!IS_ERR(cs42888->clk))
>>>> + clk_disable_unprepare(cs42888->clk);
>>>
>>> Does the device work without MCLK?
>> Yes, MCLK is required. If you can’t get the clock you should error out.
>
> Wait...Regarding this clock part, I just forgot the reason I put the code:
>
> 385 cs42888->clk = devm_clk_get(&i2c->dev, "mclk");
> 386 if (IS_ERR(cs42888->clk))
> 387 dev_warn(&i2c->dev, "failed to get the clock: %ld\n",
> 388 PTR_ERR(cs42888->clk));
>
> was because the MCLK might be provided from SoC (DAI master) so it could
> be totally controlled by CPU DAI driver, ESAI for example has its own
> dividers to derive the HCKT clock (MCLK for Tx) from ahb clock in SoC
> clock tree, in which case we might not easily pass a valid clock phandle
> via DT. (RFC to this thought.)
OK, It’s an external MCLK source, so why not just handle that in the machine driver?
Usually you would want the clock enabled/disabled in the machine driver so if you don’t get it, you can bail out there.
At least that is how I do our MCLK’s. Since you are only using the freq of the clock to derive modes, just put the clock initialization outside and just pass in the freq like you do in set_sysclk
[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 496 bytes --]
^ permalink raw reply
* Re: [PATCH 1/5] clk: sun6i: Protect CPU clock
From: Russell King - ARM Linux @ 2014-02-24 16:30 UTC (permalink / raw)
To: Maxime Ripard
Cc: Emilio Lopez, Dan Williams, Vinod Koul,
devicetree-u79uwXL29TY76Z2rM5mHXA, Mike Turquette,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1393258967-4843-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
On Mon, Feb 24, 2014 at 05:22:43PM +0100, Maxime Ripard wrote:
> Right now, AHB is an indirect child clock of the CPU clock. If that happens to
> change, since the CPU clock has no other consumers declared in Linux, it would
> be shut down, which is not really a good idea.
>
> Prevent this by forcing it enabled.
>
> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
> drivers/clk/sunxi/clk-sunxi.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
> index 23baad9..cedaf4b 100644
> --- a/drivers/clk/sunxi/clk-sunxi.c
> +++ b/drivers/clk/sunxi/clk-sunxi.c
> @@ -1301,6 +1301,14 @@ static void __init sunxi_clock_protect(void)
> clk_prepare_enable(clk);
> clk_put(clk);
> }
> +
> + /* CPU clocks - sun6i */
> + clk = clk_get(NULL, "cpu");
> + if (!IS_ERR(clk)) {
> + clk_prepare_enable(clk);
> + clk_put(clk);
> + }
This is broken. I'm not sure what's difficult to grasp about the concept
of "while a clock is in use, you should keep a reference to that clock".
That implies that if you get a clock, and then enable it, you don't
put the clock until you've disabled it.
The only reason the core doesn't check for this kind of thing is that
a clock may be shared, so it's entirely possible for a correctly written
driver to have a clock which is still enabled at put time - but enabled
by an entirely different driver.
However, that's no excuse for this kind of sloppiness.
--
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
^ permalink raw reply
* [PATCH 5/5] ARM: sun6i: dt: Add A31 DMA controller to DTSI
From: Maxime Ripard @ 2014-02-24 16:22 UTC (permalink / raw)
To: Emilio Lopez, Dan Williams, Vinod Koul
Cc: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard
In-Reply-To: <1393258967-4843-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Now that we have a DMA driver, we can add the DMA bindings in the DTSI for the
controller and the devices supported that can use DMA.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
arch/arm/boot/dts/sun6i-a31.dtsi | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index af6f87c..ad6476a 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -237,6 +237,15 @@
#size-cells = <1>;
ranges;
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun6i-a31-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <0 50 4>;
+ clocks = <&ahb1_gates 6>;
+ resets = <&ahb1_rst 6>;
+ #dma-cells = <1>;
+ };
+
pio: pinctrl@01c20800 {
compatible = "allwinner,sun6i-a31-pinctrl";
reg = <0x01c20800 0x400>;
@@ -301,6 +310,8 @@
reg-io-width = <4>;
clocks = <&apb2_gates 16>;
resets = <&apb2_rst 16>;
+ dmas = <&dma 6>, <&dma 6>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -312,6 +323,8 @@
reg-io-width = <4>;
clocks = <&apb2_gates 17>;
resets = <&apb2_rst 17>;
+ dmas = <&dma 7>, <&dma 7>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -323,6 +336,8 @@
reg-io-width = <4>;
clocks = <&apb2_gates 18>;
resets = <&apb2_rst 18>;
+ dmas = <&dma 8>, <&dma 8>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -334,6 +349,8 @@
reg-io-width = <4>;
clocks = <&apb2_gates 19>;
resets = <&apb2_rst 19>;
+ dmas = <&dma 9>, <&dma 9>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -345,6 +362,8 @@
reg-io-width = <4>;
clocks = <&apb2_gates 20>;
resets = <&apb2_rst 20>;
+ dmas = <&dma 10>, <&dma 10>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -356,6 +375,8 @@
reg-io-width = <4>;
clocks = <&apb2_gates 21>;
resets = <&apb2_rst 21>;
+ dmas = <&dma 22>, <&dma 22>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -365,6 +386,8 @@
interrupts = <0 65 4>;
clocks = <&ahb1_gates 20>, <&spi0_clk>;
clock-names = "ahb", "mod";
+ dmas = <&dma 23>, <&dma 23>;
+ dma-names = "rx", "tx";
resets = <&ahb1_rst 20>;
status = "disabled";
};
@@ -375,6 +398,8 @@
interrupts = <0 66 4>;
clocks = <&ahb1_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
+ dmas = <&dma 24>, <&dma 24>;
+ dma-names = "rx", "tx";
resets = <&ahb1_rst 21>;
status = "disabled";
};
@@ -385,6 +410,8 @@
interrupts = <0 67 4>;
clocks = <&ahb1_gates 22>, <&spi2_clk>;
clock-names = "ahb", "mod";
+ dmas = <&dma 25>, <&dma 25>;
+ dma-names = "rx", "tx";
resets = <&ahb1_rst 22>;
status = "disabled";
};
@@ -395,6 +422,8 @@
interrupts = <0 68 4>;
clocks = <&ahb1_gates 23>, <&spi3_clk>;
clock-names = "ahb", "mod";
+ dmas = <&dma 26>, <&dma 26>;
+ dma-names = "rx", "tx";
resets = <&ahb1_rst 23>;
status = "disabled";
};
--
1.9.0
^ permalink raw reply related
* [PATCH 4/5] DMA: sun6i: Add driver for the Allwinner A31 DMA controller
From: Maxime Ripard @ 2014-02-24 16:22 UTC (permalink / raw)
To: Emilio Lopez, Dan Williams, Vinod Koul
Cc: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard
In-Reply-To: <1393258967-4843-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
The Allwinner A31 has a 16 channels DMA controller that it shares with the
newer A23. Although sharing some similarities with the DMA controller of the
older Allwinner SoCs, it's significantly different, I don't expect it to be
possible to share the driver for these two.
The A31 Controller is able to memory-to-memory or memory-to-device transfers on
the 16 channels in parallel.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
.../devicetree/bindings/dma/sun6i-dma.txt | 45 +
drivers/dma/Kconfig | 8 +
drivers/dma/Makefile | 1 +
drivers/dma/sun6i-dma.c | 960 +++++++++++++++++++++
4 files changed, 1014 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/sun6i-dma.txt
create mode 100644 drivers/dma/sun6i-dma.c
diff --git a/Documentation/devicetree/bindings/dma/sun6i-dma.txt b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
new file mode 100644
index 0000000..5d7c86d
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
@@ -0,0 +1,45 @@
+Allwinner A31 DMA Controller
+
+This driver follows the generic DMA bindings defined in dma.txt.
+
+Required properties:
+
+- compatible: Must be "allwinner,sun6i-a31-dma"
+- reg: Should contain the registers base address and length
+- interrupts: Should contain a reference to the interrupt used by this device
+- clocks: Should contain a reference to the parent AHB clock
+- resets: Should contain a reference to the reset controller asserting
+ this device in reset
+- #dma-cells : Should be 1, a single cell holding a line request number
+
+Example:
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun6i-a31-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <0 50 4>;
+ clocks = <&ahb1_gates 6>;
+ resets = <&ahb1_rst 6>;
+ #dma-cells = <1>;
+ };
+
+Clients:
+
+DMA clients connected to the A31 DMA controller must use the format
+described in the dma.txt file, using a two-cell specifier for each
+channel: a phandle plus one integer cells.
+The two cells in order are:
+
+1. A phandle pointing to the DMA controller.
+2. The port ID as specified in the datasheet
+
+Example:
+spi2: spi@01c6a000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c6a000 0x1000>;
+ interrupts = <0 67 4>;
+ clocks = <&ahb1_gates 22>, <&spi2_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma 25>, <&dma 25>;
+ dma-names = "rx", "tx";
+ resets = <&ahb1_rst 22>;
+};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 605b016..7923697 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -351,6 +351,14 @@ config MOXART_DMA
help
Enable support for the MOXA ART SoC DMA controller.
+config DMA_SUN6I
+ tristate "Allwinner A31 SoCs DMA support"
+ depends on ARCH_SUNXI
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support for the DMA engine for Allwinner A31 SoCs.
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a029d0f4..18cdbad 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
obj-$(CONFIG_TI_CPPI41) += cppi41.o
obj-$(CONFIG_K3_DMA) += k3dma.o
obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
+obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
new file mode 100644
index 0000000..2649fde
--- /dev/null
+++ b/drivers/dma/sun6i-dma.c
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 2013-2014 Allwinner Tech Co., Ltd
+ * Author: Sugar <shuge-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@public.gmane.org>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "virt-dma.h"
+
+/*
+ * There's 16 physical channels that can work in parallel.
+ *
+ * However we have 30 different endpoints for our requests.
+ *
+ * Since the channels are able to handle only an unidirectional
+ * transfer, we need to allocate more virtual channels so that
+ * everyone can grab one channel.
+ *
+ * Some devices can't work in both direction (mostly because it
+ * wouldn't make sense), so we have a bit fewer virtual channels than
+ * 2 channels per endpoints.
+ */
+
+#define NR_MAX_CHANNELS 16
+#define NR_MAX_REQUESTS 30
+#define NR_MAX_VCHANS 53
+
+/*
+ * Common registers
+ */
+#define DMA_IRQ_EN(x) ((x) * 0x04)
+#define DMA_IRQ_HALF BIT(0)
+#define DMA_IRQ_PKG BIT(1)
+#define DMA_IRQ_QUEUE BIT(2)
+
+#define DMA_IRQ_CHAN_NR 8
+#define DMA_IRQ_CHAN_WIDTH 4
+
+
+#define DMA_IRQ_STAT(x) ((x) * 0x04 + 0x10)
+
+#define DMA_STAT 0x30
+
+/*
+ * Channels specific registers
+ */
+#define DMA_CHAN_ENABLE 0x00
+#define DMA_CHAN_ENABLE_START BIT(0)
+#define DMA_CHAN_ENABLE_STOP 0
+
+#define DMA_CHAN_PAUSE 0x04
+#define DMA_CHAN_PAUSE_PAUSE BIT(1)
+#define DMA_CHAN_PAUSE_RESUME 0
+
+#define DMA_CHAN_LLI_ADDR 0x08
+
+#define DMA_CHAN_CUR_CFG 0x0c
+#define DMA_CHAN_CFG_SRC_DRQ(x) ((x) & 0x1f)
+#define DMA_CHAN_CFG_SRC_IO_MODE BIT(5)
+#define DMA_CHAN_CFG_SRC_LINEAR_MODE (0 << 5)
+#define DMA_CHAN_CFG_SRC_BURST(x) (((x) & 0x3) << 7)
+#define DMA_CHAN_CFG_SRC_WIDTH(x) (((x) & 0x3) << 9)
+
+#define DMA_CHAN_CFG_DST_DRQ(x) (DMA_CHAN_CFG_SRC_DRQ(x) << 16)
+#define DMA_CHAN_CFG_DST_IO_MODE (DMA_CHAN_CFG_SRC_IO_MODE << 16)
+#define DMA_CHAN_CFG_DST_LINEAR_MODE (DMA_CHAN_CFG_SRC_LINEAR_MODE << 16)
+#define DMA_CHAN_CFG_DST_BURST(x) (DMA_CHAN_CFG_SRC_BURST(x) << 16)
+#define DMA_CHAN_CFG_DST_WIDTH(x) (DMA_CHAN_CFG_SRC_WIDTH(x) << 16)
+
+#define DMA_CHAN_CUR_SRC 0x10
+
+#define DMA_CHAN_CUR_DST 0x14
+
+#define DMA_CHAN_CUR_CNT 0x18
+
+#define DMA_CHAN_CUR_PARA 0x1c
+
+
+/*
+ * Various hardware related defines
+ */
+#define LLI_LAST_ITEM 0xfffff800
+#define NORMAL_WAIT 8
+#define DRQ_SDRAM 1
+
+/*
+ * Hardware representation of the LLI
+ *
+ * The hardware will be fed the physical address of this structure,
+ * and read its content in order to start the transfer.
+ */
+struct sun6i_dma_lli {
+ u32 cfg;
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 len;
+ u32 para;
+ dma_addr_t p_lli_next;
+ struct sun6i_dma_lli *v_lli_next;
+} __packed;
+
+
+struct sun6i_desc {
+ struct virt_dma_desc vd;
+ dma_addr_t p_lli;
+ struct sun6i_dma_lli *v_lli;
+};
+
+struct sun6i_pchan {
+ u32 idx;
+ void __iomem *base;
+ struct sun6i_vchan *vchan;
+ struct sun6i_desc *desc;
+ struct sun6i_desc *done;
+};
+
+struct sun6i_vchan {
+ struct virt_dma_chan vc;
+ struct list_head node;
+ struct dma_slave_config cfg;
+ struct sun6i_pchan *phy;
+ u8 port;
+};
+
+struct sun6i_dma_dev {
+ struct dma_device slave;
+ void __iomem *base;
+ struct clk *clk;
+ struct reset_control *rstc;
+ spinlock_t lock;
+ struct tasklet_struct task;
+ struct list_head pending;
+ struct dma_pool *pool;
+ struct sun6i_pchan *pchans;
+ struct sun6i_vchan *vchans;
+};
+
+static struct device *chan2dev(struct dma_chan *chan)
+{
+ return &chan->dev->device;
+}
+
+static inline struct sun6i_dma_dev *to_sun6i_dma_dev(struct dma_device *d)
+{
+ return container_of(d, struct sun6i_dma_dev, slave);
+}
+
+static inline struct sun6i_vchan *to_sun6i_vchan(struct dma_chan *chan)
+{
+ return container_of(chan, struct sun6i_vchan, vc.chan);
+}
+
+static inline struct sun6i_desc *
+to_sun6i_desc(struct dma_async_tx_descriptor *tx)
+{
+ return container_of(tx, struct sun6i_desc, vd.tx);
+}
+
+static inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev)
+{
+ pr_debug("Common register:\n"
+ "\tmask0(%04x): 0x%08x\n"
+ "\tmask1(%04x): 0x%08x\n"
+ "\tpend0(%04x): 0x%08x\n"
+ "\tpend1(%04x): 0x%08x\n"
+ "\tstats(%04x): 0x%08x\n",
+ DMA_IRQ_EN(0), readl(sdev->base + DMA_IRQ_EN(0)),
+ DMA_IRQ_EN(1), readl(sdev->base + DMA_IRQ_EN(1)),
+ DMA_IRQ_STAT(0), readl(sdev->base + DMA_IRQ_STAT(0)),
+ DMA_IRQ_STAT(1), readl(sdev->base + DMA_IRQ_STAT(1)),
+ DMA_STAT, readl(sdev->base + DMA_STAT));
+}
+
+static inline void sun6i_dma_dump_chan_regs(struct sun6i_pchan *pchan)
+{
+ pr_debug("Chan %d reg: 0x%x\n"
+ "\t___en(%04x): \t0x%08x\n"
+ "\tpause(%04x): \t0x%08x\n"
+ "\tstart(%04x): \t0x%08x\n"
+ "\t__cfg(%04x): \t0x%08x\n"
+ "\t__src(%04x): \t0x%08x\n"
+ "\t__dst(%04x): \t0x%08x\n"
+ "\tcount(%04x): \t0x%08x\n"
+ "\t_para(%04x): \t0x%08x\n\n",
+ pchan->idx, __virt_to_phys((unsigned long)pchan->base),
+ DMA_CHAN_ENABLE,
+ readl(pchan->base + DMA_CHAN_ENABLE),
+ DMA_CHAN_PAUSE,
+ readl(pchan->base + DMA_CHAN_PAUSE),
+ DMA_CHAN_LLI_ADDR,
+ readl(pchan->base + DMA_CHAN_LLI_ADDR),
+ DMA_CHAN_CUR_CFG,
+ readl(pchan->base + DMA_CHAN_CUR_CFG),
+ DMA_CHAN_CUR_SRC,
+ readl(pchan->base + DMA_CHAN_CUR_SRC),
+ DMA_CHAN_CUR_DST,
+ readl(pchan->base + DMA_CHAN_CUR_DST),
+ DMA_CHAN_CUR_CNT,
+ readl(pchan->base + DMA_CHAN_CUR_CNT),
+ DMA_CHAN_CUR_PARA,
+ readl(pchan->base + DMA_CHAN_CUR_PARA));
+}
+
+static inline u8 convert_burst(u8 maxburst)
+{
+ if (maxburst == 1 || maxburst > 16)
+ return 0;
+
+ return ilog2(maxburst) - 1;
+}
+
+static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
+{
+ switch (addr_width) {
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ return 1;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
+ struct sun6i_dma_lli *next,
+ dma_addr_t next_phy,
+ struct sun6i_desc *txd)
+{
+ if ((!prev && !txd) || !next)
+ return NULL;
+
+ if (!prev) {
+ txd->p_lli = next_phy;
+ txd->v_lli = next;
+ } else {
+ prev->p_lli_next = next_phy;
+ prev->v_lli_next = next;
+ }
+
+ next->p_lli_next = LLI_LAST_ITEM;
+ next->v_lli_next = NULL;
+
+ return next;
+}
+
+static inline void sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
+ dma_addr_t src,
+ dma_addr_t dst, u32 len,
+ struct dma_slave_config *config)
+{
+ u32 src_width, dst_width, src_burst, dst_burst;
+
+ if (!config)
+ return;
+
+ src_burst = convert_burst(config->src_maxburst);
+ dst_burst = convert_burst(config->dst_maxburst);
+
+ src_width = convert_buswidth(config->src_addr_width);
+ dst_width = convert_buswidth(config->dst_addr_width);
+
+ lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
+ DMA_CHAN_CFG_SRC_WIDTH(src_width) |
+ DMA_CHAN_CFG_DST_BURST(dst_burst) |
+ DMA_CHAN_CFG_DST_WIDTH(dst_width);
+
+ lli->src = src;
+ lli->dst = dst;
+ lli->len = len;
+ lli->para = NORMAL_WAIT;
+
+}
+
+static inline void sun6i_dma_dump_lli(struct sun6i_vchan *vchan,
+ struct sun6i_dma_lli *lli)
+{
+ dev_dbg(chan2dev(&vchan->vc.chan),
+ "\n\tdesc: p - 0x%08x v - 0x%08x\n"
+ "\t\tc - 0x%08x s - 0x%08x d - 0x%08x\n"
+ "\t\tl - 0x%08x p - 0x%08x n - 0x%08x\n",
+ __virt_to_phys((unsigned long)lli), (u32)lli,
+ lli->cfg, lli->src, lli->dst,
+ lli->len, lli->para, lli->p_lli_next);
+}
+
+static void sun6i_dma_free_desc(struct virt_dma_desc *vd)
+{
+ struct sun6i_desc *txd = to_sun6i_desc(&vd->tx);
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vd->tx.chan->device);
+ struct sun6i_dma_lli *v_lli, *v_next;
+ dma_addr_t p_lli, p_next;
+
+ if (unlikely(!txd))
+ return;
+
+ p_lli = txd->p_lli;
+ v_lli = txd->v_lli;
+
+ while (v_lli) {
+ v_next = v_lli->v_lli_next;
+ p_next = v_lli->p_lli_next;
+
+ dma_pool_free(sdev->pool, v_lli, p_lli);
+
+ v_lli = v_next;
+ p_lli = p_next;
+ }
+
+ kfree(txd);
+}
+
+static int sun6i_dma_terminate_all(struct sun6i_vchan *vchan)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
+ struct sun6i_pchan *pchan = vchan->phy;
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock(&sdev->lock);
+ list_del_init(&vchan->node);
+ spin_unlock(&sdev->lock);
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ vchan_get_all_descriptors(&vchan->vc, &head);
+
+ if (pchan) {
+ writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE);
+ writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE);
+
+ vchan->phy = NULL;
+ pchan->vchan = NULL;
+ pchan->desc = NULL;
+ pchan->done = NULL;
+ }
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+ vchan_dma_desc_free_list(&vchan->vc, &head);
+
+ return 0;
+}
+
+static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
+ struct virt_dma_desc *desc = vchan_next_desc(&vchan->vc);
+ struct sun6i_pchan *pchan = vchan->phy;
+ u32 irq_val, irq_reg, irq_offset;
+
+ if (!pchan)
+ return -EAGAIN;
+
+ if (!desc) {
+ pchan->desc = NULL;
+ pchan->done = NULL;
+ return -EAGAIN;
+ }
+
+ list_del(&desc->node);
+
+ pchan->desc = to_sun6i_desc(&desc->tx);
+ pchan->done = NULL;
+
+ sun6i_dma_dump_lli(vchan, pchan->desc->v_lli);
+
+ irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
+ irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
+
+ irq_val = readl(sdev->base + DMA_IRQ_EN(irq_offset));
+ irq_val |= DMA_IRQ_QUEUE << (irq_offset * DMA_IRQ_CHAN_WIDTH);
+ writel(irq_val, sdev->base + DMA_IRQ_EN(irq_offset));
+
+ writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
+ writel(DMA_CHAN_ENABLE_START, pchan->base + DMA_CHAN_ENABLE);
+
+ sun6i_dma_dump_com_regs(sdev);
+ sun6i_dma_dump_chan_regs(pchan);
+
+ return 0;
+}
+
+static void sun6i_dma_tasklet(unsigned long data)
+{
+ struct sun6i_dma_dev *sdev = (struct sun6i_dma_dev *)data;
+ struct sun6i_vchan *vchan;
+ struct sun6i_pchan *pchan;
+ unsigned int pchan_alloc = 0;
+ unsigned int pchan_idx;
+
+ list_for_each_entry(vchan, &sdev->slave.channels, vc.chan.device_node) {
+ spin_lock_irq(&vchan->vc.lock);
+
+ pchan = vchan->phy;
+
+ if (pchan && pchan->done) {
+ if (sun6i_dma_start_desc(vchan)) {
+ /*
+ * No current txd associated with this channel
+ */
+ dev_dbg(sdev->slave.dev, "pchan %u: free\n",
+ pchan->idx);
+
+ /* Mark this channel free */
+ vchan->phy = NULL;
+ pchan->vchan = NULL;
+ }
+ }
+ spin_unlock_irq(&vchan->vc.lock);
+ }
+
+ spin_lock_irq(&sdev->lock);
+ for (pchan_idx = 0; pchan_idx < NR_MAX_CHANNELS; pchan_idx++) {
+ pchan = &sdev->pchans[pchan_idx];
+
+ if (pchan->vchan == NULL && !list_empty(&sdev->pending)) {
+ vchan = list_first_entry(&sdev->pending,
+ struct sun6i_vchan, node);
+
+ /* remove from pending channels */
+ list_del_init(&vchan->node);
+ pchan_alloc |= BIT(pchan_idx);
+
+ /* Mark this channel allocated */
+ pchan->vchan = vchan;
+ vchan->phy = pchan;
+ dev_dbg(sdev->slave.dev, "pchan %u: alloc vchan %p\n",
+ pchan->idx, &vchan->vc);
+ }
+ }
+ spin_unlock_irq(&sdev->lock);
+
+ for (pchan_idx = 0; pchan_idx < NR_MAX_CHANNELS; pchan_idx++) {
+ if (pchan_alloc & BIT(pchan_idx)) {
+ pchan = sdev->pchans + pchan_idx;
+ vchan = pchan->vchan;
+ if (vchan) {
+ spin_lock_irq(&vchan->vc.lock);
+ sun6i_dma_start_desc(vchan);
+ spin_unlock_irq(&vchan->vc.lock);
+ }
+ }
+ }
+}
+
+static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
+{
+ struct sun6i_dma_dev *sdev = (struct sun6i_dma_dev *)dev_id;
+ struct sun6i_vchan *vchan;
+ struct sun6i_pchan *pchan;
+ int i, j, ret = 0;
+ u32 status;
+
+ for (i = 0; i < 2; i++) {
+ status = readl(sdev->base + DMA_IRQ_STAT(i));
+ if (!status) {
+ ret |= IRQ_NONE;
+ continue;
+ }
+
+ dev_dbg(sdev->slave.dev, "DMA irq status %s: 0x%x\n",
+ i ? "high" : "low", status);
+
+ writel(status, sdev->base + DMA_IRQ_STAT(i));
+
+ for (j = 0; (j < 8) && status; j++) {
+ if (status & DMA_IRQ_QUEUE) {
+ pchan = sdev->pchans + j;
+ vchan = pchan->vchan;
+
+ if (vchan) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&vchan->vc.lock,
+ flags);
+ vchan_cookie_complete(&pchan->desc->vd);
+ pchan->done = pchan->desc;
+ spin_unlock_irqrestore(&vchan->vc.lock,
+ flags);
+ }
+ }
+
+ status = status >> 4;
+ }
+
+ ret |= IRQ_HANDLED;
+ }
+
+ if (ret == IRQ_HANDLED)
+ tasklet_schedule(&sdev->task);
+
+ return ret;
+}
+
+static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ struct dma_slave_config *sconfig = &vchan->cfg;
+ struct sun6i_dma_lli *v_lli;
+ struct sun6i_desc *txd;
+ dma_addr_t p_lli;
+
+ dev_dbg(chan2dev(chan),
+ "%s; chan: %d, dest: 0x%08x, src: 0x%08x, len: 0x%08x. flags: 0x%08lx\n",
+ __func__, vchan->vc.chan.chan_id, dest, src, len, flags);
+
+ if (!len)
+ return NULL;
+
+ txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+ if (!txd)
+ return NULL;
+
+ v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+ if (!v_lli) {
+ dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
+ kfree(txd);
+ return NULL;
+ }
+
+ sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig);
+ v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
+ DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
+ DMA_CHAN_CFG_DST_LINEAR_MODE |
+ DMA_CHAN_CFG_SRC_LINEAR_MODE;
+
+ sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
+
+ sun6i_dma_dump_lli(vchan, v_lli);
+
+ return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ struct dma_slave_config *sconfig = &vchan->cfg;
+ struct sun6i_dma_lli *v_lli, *prev = NULL;
+ struct sun6i_desc *txd;
+ struct scatterlist *sg;
+ dma_addr_t p_lli;
+ int i;
+
+ if (!sgl)
+ return NULL;
+
+ txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+ if (!txd)
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+ if (!v_lli) {
+ kfree(txd);
+ return NULL;
+ }
+
+ if (dir == DMA_MEM_TO_DEV) {
+ sun6i_dma_cfg_lli(v_lli, sg_dma_address(sg),
+ sconfig->dst_addr, sg_dma_len(sg),
+ sconfig);
+ v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE |
+ DMA_CHAN_CFG_SRC_LINEAR_MODE |
+ DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
+ DMA_CHAN_CFG_DST_DRQ(vchan->port);
+
+ dev_dbg(chan2dev(chan), "%s; chan: %d, dest: 0x%08x, "
+ "src: 0x%08x, len: 0x%08x. flags: 0x%08lx\n",
+ __func__, vchan->vc.chan.chan_id,
+ sconfig->dst_addr, sg_dma_address(sg),
+ sg_dma_len(sg), flags);
+
+ } else if (dir == DMA_DEV_TO_MEM) {
+ sun6i_dma_cfg_lli(v_lli, sconfig->src_addr,
+ sg_dma_address(sg), sg_dma_len(sg),
+ sconfig);
+ v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE |
+ DMA_CHAN_CFG_SRC_IO_MODE |
+ DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
+ DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+
+ dev_dbg(chan2dev(chan), "%s; chan: %d, dest: 0x%08x, "
+ "src: 0x%08x, len: 0x%08x. flags: 0x%08lx\n",
+ __func__, vchan->vc.chan.chan_id,
+ sg_dma_address(sg), sconfig->src_addr,
+ sg_dma_len(sg), flags);
+ }
+
+ prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
+ }
+
+#ifdef DEBUG
+ dev_dbg(chan2dev(chan), "First: 0x%08x\n", txd->p_lli);
+ for (prev = txd->v_lli; prev != NULL; prev = prev->v_lli_next)
+ sun6i_dma_dump_lli(vchan, prev);
+#endif
+
+ return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+}
+
+static int sun6i_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ struct sun6i_pchan *pchan = vchan->phy;
+ unsigned long flags;
+ int ret = 0;
+
+ switch (cmd) {
+ case DMA_RESUME:
+ dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ if (pchan) {
+ writel(DMA_CHAN_PAUSE_RESUME,
+ pchan->base + DMA_CHAN_PAUSE);
+ } else if (!list_empty(&vchan->vc.desc_issued)) {
+ spin_lock(&sdev->lock);
+ list_add_tail(&vchan->node, &sdev->pending);
+ spin_unlock(&sdev->lock);
+ }
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+ break;
+
+ case DMA_PAUSE:
+ dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc);
+
+ if (pchan) {
+ writel(DMA_CHAN_PAUSE_PAUSE,
+ pchan->base + DMA_CHAN_PAUSE);
+ } else {
+ spin_lock(&sdev->lock);
+ list_del_init(&vchan->node);
+ spin_unlock(&sdev->lock);
+ }
+ break;
+
+ case DMA_TERMINATE_ALL:
+ ret = sun6i_dma_terminate_all(vchan);
+ break;
+ case DMA_SLAVE_CONFIG:
+ memcpy(&vchan->cfg, (struct dma_slave_config *)arg,
+ sizeof(struct dma_slave_config));
+ break;
+ default:
+ ret = -ENXIO;
+ break;
+ }
+ return ret;
+}
+
+static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *state)
+{
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ struct sun6i_pchan *pchan = vchan->phy;
+ struct sun6i_dma_lli *lli;
+ struct virt_dma_desc *vd;
+ struct sun6i_desc *txd;
+ enum dma_status ret;
+ unsigned long flags;
+ size_t bytes = 0;
+
+ ret = dma_cookie_status(chan, cookie, state);
+ if (ret == DMA_COMPLETE)
+ return ret;
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ vd = vchan_find_desc(&vchan->vc, cookie);
+ txd = to_sun6i_desc(&vd->tx);
+
+ if (vd) {
+ for (lli = txd->v_lli; lli != NULL; lli = lli->v_lli_next)
+ bytes += lli->len;
+ } else if (!pchan || !pchan->desc) {
+ bytes = 0;
+ } else {
+ bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+ }
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+ dma_set_residue(state, bytes);
+
+ return ret;
+}
+
+static void sun6i_dma_issue_pending(struct dma_chan *chan)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ if (vchan_issue_pending(&vchan->vc)) {
+ spin_lock(&sdev->lock);
+
+ if (!vchan->phy) {
+ if (list_empty(&vchan->node)) {
+ list_add_tail(&vchan->node, &sdev->pending);
+ tasklet_schedule(&sdev->task);
+ dev_dbg(chan2dev(chan), "vchan %p: issued\n",
+ &vchan->vc);
+ }
+ }
+
+ spin_unlock(&sdev->lock);
+ } else {
+ dev_dbg(chan2dev(chan), "vchan %p: nothing to issue\n",
+ &vchan->vc);
+ }
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+}
+
+static int sun6i_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ return 0;
+}
+
+static void sun6i_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdev->lock, flags);
+ list_del_init(&vchan->node);
+ spin_unlock_irqrestore(&sdev->lock, flags);
+
+ vchan_free_chan_resources(&vchan->vc);
+}
+
+static inline void sun6i_dma_free(struct sun6i_dma_dev *sdc)
+{
+ int i;
+
+ for (i = 0; i < NR_MAX_VCHANS; i++) {
+ struct sun6i_vchan *vchan = &sdc->vchans[i];
+
+ list_del(&vchan->vc.chan.device_node);
+ tasklet_kill(&vchan->vc.task);
+ }
+
+ tasklet_kill(&sdc->task);
+}
+
+static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct sun6i_dma_dev *sdev = ofdma->of_dma_data;
+ struct sun6i_vchan *vchan;
+ struct dma_chan *chan;
+ u8 port = dma_spec->args[0];
+
+ if (port > NR_MAX_REQUESTS)
+ return NULL;
+
+ chan = dma_get_any_slave_channel(&sdev->slave);
+ if (!chan)
+ return NULL;
+
+ vchan = to_sun6i_vchan(chan);
+ vchan->port = port;
+
+ return chan;
+}
+
+static int sun6i_dma_probe(struct platform_device *pdev)
+{
+ struct sun6i_dma_dev *sdc;
+ struct resource *res;
+ int irq;
+ int ret, i;
+
+ sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
+ if (!sdc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sdc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sdc->base))
+ return PTR_ERR(sdc->base);
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(&pdev->dev, irq, sun6i_dma_interrupt, 0,
+ dev_name(&pdev->dev), sdc);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ return ret;
+ }
+
+ sdc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sdc->clk)) {
+ dev_err(&pdev->dev, "No clock specified\n");
+ return PTR_ERR(sdc->clk);
+ }
+
+ sdc->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(sdc->rstc)) {
+ dev_err(&pdev->dev, "No reset controller specified\n");
+ return PTR_ERR(sdc->rstc);
+ }
+
+ sdc->pool = dma_pool_create(dev_name(&pdev->dev), &pdev->dev,
+ sizeof(struct sun6i_dma_lli), 4, 0);
+ if (!sdc->pool) {
+ dev_err(&pdev->dev, "No memory for descriptors dma pool\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, sdc);
+ INIT_LIST_HEAD(&sdc->pending);
+ spin_lock_init(&sdc->lock);
+
+ dma_cap_set(DMA_PRIVATE, sdc->slave.cap_mask);
+ dma_cap_set(DMA_MEMCPY, sdc->slave.cap_mask);
+ dma_cap_set(DMA_SLAVE, sdc->slave.cap_mask);
+
+ INIT_LIST_HEAD(&sdc->slave.channels);
+ sdc->slave.device_alloc_chan_resources = sun6i_dma_alloc_chan_resources;
+ sdc->slave.device_free_chan_resources = sun6i_dma_free_chan_resources;
+ sdc->slave.device_tx_status = sun6i_dma_tx_status;
+ sdc->slave.device_issue_pending = sun6i_dma_issue_pending;
+ sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg;
+ sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy;
+ sdc->slave.device_control = sun6i_dma_control;
+ sdc->slave.chancnt = NR_MAX_VCHANS;
+
+ sdc->slave.dev = &pdev->dev;
+
+ sdc->pchans = devm_kzalloc(&pdev->dev,
+ NR_MAX_CHANNELS * sizeof(struct sun6i_pchan),
+ GFP_KERNEL);
+ if (!sdc->pchans) {
+ ret = -ENOMEM;
+ goto err_dma_pool_destroy;
+ }
+
+ sdc->vchans = devm_kzalloc(&pdev->dev,
+ NR_MAX_VCHANS * sizeof(struct sun6i_vchan),
+ GFP_KERNEL);
+ if (!sdc->vchans) {
+ ret = -ENOMEM;
+ goto err_dma_pool_destroy;
+ }
+
+ tasklet_init(&sdc->task, sun6i_dma_tasklet, (unsigned long)sdc);
+
+ for (i = 0; i < NR_MAX_CHANNELS; i++) {
+ struct sun6i_pchan *pchan = &sdc->pchans[i];
+
+ pchan->idx = i;
+ pchan->base = sdc->base + 0x100 + i * 0x40;
+ }
+
+ for (i = 0; i < NR_MAX_VCHANS; i++) {
+ struct sun6i_vchan *vchan = &sdc->vchans[i];
+
+ INIT_LIST_HEAD(&vchan->node);
+ vchan->vc.desc_free = sun6i_dma_free_desc;
+ vchan_init(&vchan->vc, &sdc->slave);
+ }
+
+ reset_control_deassert(sdc->rstc);
+
+ clk_prepare_enable(sdc->clk);
+
+ ret = dma_async_device_register(&sdc->slave);
+ if (ret) {
+ dev_warn(&pdev->dev, "Failed to register DMA engine device\n");
+ goto err_clk_disable;
+ }
+
+ ret = of_dma_controller_register(pdev->dev.of_node, sun6i_dma_of_xlate,
+ sdc);
+ if (ret) {
+ dev_err(&pdev->dev, "of_dma_controller_register failed\n");
+ goto err_dma_unregister;
+ }
+
+ return 0;
+
+err_dma_unregister:
+ dma_async_device_unregister(&sdc->slave);
+err_clk_disable:
+ clk_disable_unprepare(sdc->clk);
+ reset_control_assert(sdc->rstc);
+ sun6i_dma_free(sdc);
+err_dma_pool_destroy:
+ dma_pool_destroy(sdc->pool);
+ return ret;
+}
+
+static int sun6i_dma_remove(struct platform_device *pdev)
+{
+ struct sun6i_dma_dev *sdc = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&sdc->slave);
+
+ clk_disable_unprepare(sdc->clk);
+ reset_control_assert(sdc->rstc);
+
+ sun6i_dma_free(sdc);
+
+ dma_pool_destroy(sdc->pool);
+
+ return 0;
+}
+
+static struct of_device_id sun6i_dma_match[] = {
+ { .compatible = "allwinner,sun6i-a31-dma" }
+};
+
+static struct platform_driver sun6i_dma_driver = {
+ .probe = sun6i_dma_probe,
+ .remove = sun6i_dma_remove,
+ .driver = {
+ .name = "sun6i-dma",
+ .of_match_table = sun6i_dma_match,
+ },
+};
+module_platform_driver(sun6i_dma_driver);
+
+MODULE_DESCRIPTION("Allwinner A31 DMA Controller Driver");
+MODULE_AUTHOR("Sugar <shuge-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf@public.gmane.org>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
+MODULE_LICENSE("GPL");
--
1.9.0
^ permalink raw reply related
* [PATCH 3/5] clk: sun6i: Protect SDRAM gating bit
From: Maxime Ripard @ 2014-02-24 16:22 UTC (permalink / raw)
To: Emilio Lopez, Dan Williams, Vinod Koul
Cc: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard
In-Reply-To: <1393258967-4843-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Prevent the SDRAM controller from being gated by force-enabling it in the clock
driver.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/clk/sunxi/clk-sunxi.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 6cfcd23..d9b4a41 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1302,6 +1302,13 @@ static void __init sunxi_clock_protect(void)
clk_put(clk);
}
+ /* DDR Gating clock - sun6i */
+ clk = clk_get(NULL, "ahb1_sdram");
+ if (!IS_ERR(clk)) {
+ clk_prepare_enable(clk);
+ clk_put(clk);
+ }
+
/* CPU clocks - sun6i */
clk = clk_get(NULL, "cpu");
if (!IS_ERR(clk)) {
--
1.9.0
^ permalink raw reply related
* [PATCH 2/5] clk: sun6i: Reparent AHB clock on PLL6
From: Maxime Ripard @ 2014-02-24 16:22 UTC (permalink / raw)
To: Emilio Lopez, Dan Williams, Vinod Koul
Cc: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard
In-Reply-To: <1393258967-4843-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
In order for the DMA controller to work for SDRAM to devices transfers, the AHB
clock should be reparented on the PLL6.
Force that parenting in the clock driver.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/clk/sunxi/clk-sunxi.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index cedaf4b..6cfcd23 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1286,7 +1286,7 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
*/
static void __init sunxi_clock_protect(void)
{
- struct clk *clk;
+ struct clk *clk, *parent;
/* memory bus clock - sun5i+ */
clk = clk_get(NULL, "mbus");
@@ -1309,6 +1309,22 @@ static void __init sunxi_clock_protect(void)
clk_put(clk);
}
+ clk = clk_get(NULL, "ahb1_mux");
+ if (IS_ERR(clk)) {
+ pr_err("Couldn't get AHB1 Mux\n");
+ return;
+ }
+
+ parent = clk_get(NULL, "pll6");
+ if (IS_ERR(clk)) {
+ pr_err("Couldn't get PLL6\n");
+ return;
+ }
+
+ clk_set_parent(clk, parent);
+
+ clk_put(clk);
+ clk_put(parent);
}
static void __init sunxi_init_clocks(void)
--
1.9.0
^ permalink raw reply related
* [PATCH 1/5] clk: sun6i: Protect CPU clock
From: Maxime Ripard @ 2014-02-24 16:22 UTC (permalink / raw)
To: Emilio Lopez, Dan Williams, Vinod Koul
Cc: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard
In-Reply-To: <1393258967-4843-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Right now, AHB is an indirect child clock of the CPU clock. If that happens to
change, since the CPU clock has no other consumers declared in Linux, it would
be shut down, which is not really a good idea.
Prevent this by forcing it enabled.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/clk/sunxi/clk-sunxi.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 23baad9..cedaf4b 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1301,6 +1301,14 @@ static void __init sunxi_clock_protect(void)
clk_prepare_enable(clk);
clk_put(clk);
}
+
+ /* CPU clocks - sun6i */
+ clk = clk_get(NULL, "cpu");
+ if (!IS_ERR(clk)) {
+ clk_prepare_enable(clk);
+ clk_put(clk);
+ }
+
}
static void __init sunxi_init_clocks(void)
--
1.9.0
^ permalink raw reply related
* [PATCH 0/5] Add support for the Allwinner A31 DMA Controller
From: Maxime Ripard @ 2014-02-24 16:22 UTC (permalink / raw)
To: Emilio Lopez, Dan Williams, Vinod Koul
Cc: Mike Turquette, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
dmaengine-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Maxime Ripard
Hi,
This patchset adds support for the DMA controller found in the
Allwinner A31 and A23 SoCs.
This has been tested using the newly introduced SPI driver on an A31
EVK. Support for DMA-driven SPI transfers will be the subject of
another patch serie.
Thanks,
Maxime
Maxime Ripard (5):
clk: sun6i: Protect CPU clock
clk: sun6i: Reparent AHB clock on PLL6
clk: sun6i: Protect SDRAM gating bit
DMA: sun6i: Add driver for the Allwinner A31 DMA controller
ARM: sun6i: dt: Add A31 DMA controller to DTSI
.../devicetree/bindings/dma/sun6i-dma.txt | 45 +
arch/arm/boot/dts/sun6i-a31.dtsi | 29 +
drivers/clk/sunxi/clk-sunxi.c | 33 +-
drivers/dma/Kconfig | 8 +
drivers/dma/Makefile | 1 +
drivers/dma/sun6i-dma.c | 960 +++++++++++++++++++++
6 files changed, 1075 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/dma/sun6i-dma.txt
create mode 100644 drivers/dma/sun6i-dma.c
--
1.9.0
^ permalink raw reply
* Re: [PATCH] ASoC: cs42888: Add codec driver support
From: Nicolin Chen @ 2014-02-24 16:06 UTC (permalink / raw)
To: Austin, Brian
Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
alsa-devel@alsa-project.org, pawel.moll@arm.com,
ijc+devicetree@hellion.org.uk, Mark Brown,
linux-doc@vger.kernel.org, Liam Girdwood, Handrigan, Paul,
linux-kernel@vger.kernel.org, robh+dt@kernel.org, rob@landley.net,
galak@codeaurora.org, grant.likely@linaro.org
In-Reply-To: <B745DBDD-8A64-4B98-819B-72F8AFF602DE@cirrus.com>
On Mon, Feb 24, 2014 at 03:52:24PM +0000, Austin, Brian wrote:
> >> + if (!IS_ERR(cs42888->clk))
> >> + clk_disable_unprepare(cs42888->clk);
> >
> > Does the device work without MCLK?
> Yes, MCLK is required. If you can’t get the clock you should error out.
Wait...Regarding this clock part, I just forgot the reason I put the code:
385 cs42888->clk = devm_clk_get(&i2c->dev, "mclk");
386 if (IS_ERR(cs42888->clk))
387 dev_warn(&i2c->dev, "failed to get the clock: %ld\n",
388 PTR_ERR(cs42888->clk));
was because the MCLK might be provided from SoC (DAI master) so it could
be totally controlled by CPU DAI driver, ESAI for example has its own
dividers to derive the HCKT clock (MCLK for Tx) from ahb clock in SoC
clock tree, in which case we might not easily pass a valid clock phandle
via DT. (RFC to this thought.)
Thank you,
Nicolin Chen
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply
* Re: [RFCv1 4/4] mfd: twl4030-madc: Move driver to drivers/iio/adc
From: Lee Jones @ 2014-02-24 16:05 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Sebastian Reichel, Marek Belisko, Jonathan Cameron, Samuel Ortiz,
Lars-Peter Clausen, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1392403586-30540-4-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> This is a driver for an A/D converter, which belongs into
> drivers/iio/adc.
>
> Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> ---
> drivers/iio/adc/Kconfig | 10 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/twl4030-madc.c | 922 +++++++++++++++++++++++++++++++++++++++++
> drivers/mfd/Kconfig | 10 -
> drivers/mfd/Makefile | 1 -
> drivers/mfd/twl4030-madc.c | 922 -----------------------------------------
> 6 files changed, 933 insertions(+), 933 deletions(-)
> create mode 100644 drivers/iio/adc/twl4030-madc.c
> delete mode 100644 drivers/mfd/twl4030-madc.c
For the MFD changes:
Acked-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [RFCv1 1/4] mfd: twl4030-madc: Use managed resources
From: Lee Jones @ 2014-02-24 16:04 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Sebastian Reichel, Marek Belisko, Jonathan Cameron, Samuel Ortiz,
Lars-Peter Clausen, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1392403586-30540-1-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> Update twl4030-madc driver to use managed resources.
>
> Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> ---
> drivers/mfd/twl4030-madc.c | 15 ++++++---------
> 1 file changed, 6 insertions(+), 9 deletions(-)
Acked-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: devicetree repository separation/migration
From: Ian Campbell @ 2014-02-24 15:59 UTC (permalink / raw)
To: Sascha Hauer
Cc: Frank Rowand, Jason Cooper, Grant Likely, Rob Herring,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
galak-sgV2jX0FEOL9JmXXK+q4OQ, rob-VoJi6FS/r0vR7s880joybQ,
devicetree-u79uwXL29TY76Z2rM5mHXA,
devicetree-spec-u79uwXL29TY76Z2rM5mHXA,
devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20140221141136.GI17250-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On Fri, 2014-02-21 at 15:11 +0100, Sascha Hauer wrote:
> Ians dts repository is a good start, but it contains a complete kernel
> history and this is not very suitable as a submodule for other
> projects.
It only contains the full history for the files which it contains, not a
complete kernel history. This is deliberate so that "git annotate" etc
still works to tell you where a particular line came from.
The are a lot of merge NULL-commits which aren't strictly needed (they
have no content and only a single parent) but I didn't manage to get git
rewrite-branch to omit them. They are mostly harmless I think.
I'm not sure how any of that makes it unsuitable for use as a submodule
though, the history contained in a git tree seems pretty orthogonal to
that to me.
TBH, I'm not sure what the requirements for a submodule are -- IME when
something is used as a submodule it is up to the outer git tree to call
into the inner build system in the correct way, whatever that may be.
Ian.
--
To unsubscribe from this list: send the line "unsubscribe devicetree-spec" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCHv1 5/6] HSI: Introduce OMAP SSI driver
From: Nishanth Menon @ 2014-02-24 15:56 UTC (permalink / raw)
To: Mark Rutland, Sebastian Reichel
Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
Carlos Chinea, Tony Lindgren, grant.likely@linaro.org,
rob.herring@calxeda.com, Pawel Moll, Stephen Warren, Ian Campbell,
Rob Landley, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org,
Pali Rohár,
Ивайло Димитров,
Joni Lapilainen, Aaro Koskinen
In-Reply-To: <20140224155132.GK28555@e106331-lin.cambridge.arm.com>
On 02/24/2014 09:51 AM, Mark Rutland wrote:
> On Sun, Feb 23, 2014 at 11:50:00PM +0000, Sebastian Reichel wrote:
[...]
>> +static int omap_ssi_port_runtime_suspend(struct device *dev)
>> +{
>> + struct hsi_port *port = dev_get_drvdata(dev);
>> + struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
>> + struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
>> + struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
>> +
>> + dev_dbg(dev, "port runtime suspend!\n");
>> +
>> + ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);
>> + if (omap_ssi->get_loss)
>> + omap_port->loss_count =
>> + (*omap_ssi->get_loss)(ssi->device.parent);
>
> You don't need to do (*struct->func)(args) when invoking a function
> pointer. You can jsut have struct->func(args) as we do elsewhere. This
> can be:
>
> omap_ssi->get_loss(ssi->device.parent)
>
> This should be fixed up in the other sites too.
in fact, we should stop expecting that service and drivers should
manage their own context_loss detection
Examples:
MMC:
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0a82e06e6183a252608df48cc4793b83e2d73dfd
DSS: http://marc.info/?l=linux-omap&m=139272358619064&w=2
--
Regards,
Nishanth Menon
^ permalink raw reply
* Re: [PATCH] ASoC: cs42888: Add codec driver support
From: Austin, Brian @ 2014-02-24 15:52 UTC (permalink / raw)
To: Mark Brown
Cc: Nicolin Chen, Handrigan, Paul, robh+dt@kernel.org,
pawel.moll@arm.com, mark.rutland@arm.com,
ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
rob@landley.net, Liam Girdwood, grant.likely@linaro.org,
devicetree@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, alsa-devel@alsa-project.org
In-Reply-To: <20140224113011.GE25940@sirena.org.uk>
[-- Attachment #1: Type: text/plain, Size: 714 bytes --]
>
>> + /* Disable auto-mute */
>> + regmap_update_bits(cs42888->regmap, CS42888_TXCTL,
>> + CS42888_TXCTL_AMUTE | CS42888_TXCTL_DAC_SZC_MASK,
>> + CS42888_TXCTL_DAC_SZC_SR);
>
> Does this interfere with the manual mute controls or is it a separate
> thing? If it plays nicely with the manual controls it's probably better
> to leave it enabled since it improves performance in some benchmarks
> (that's why hardware tends to have the feature).
Auto-Mute should be enabled by default.
>
>> + if (!IS_ERR(cs42888->clk))
>> + clk_disable_unprepare(cs42888->clk);
>
> Does the device work without MCLK?
Yes, MCLK is required. If you can’t get the clock you should error out.
[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 496 bytes --]
^ permalink raw reply
* Re: [RFC PATCH v3 2/9] staging: imx-drm: Add temporary copies of v4l2-of parsing functions
From: Russell King - ARM Linux @ 2014-02-24 15:52 UTC (permalink / raw)
To: Philipp Zabel
Cc: devel, devicetree, Greg Kroah-Hartman, dri-devel, kernel,
Grant Likely, linux-arm-kernel
In-Reply-To: <1392723370-4772-3-git-send-email-p.zabel@pengutronix.de>
On Tue, Feb 18, 2014 at 12:36:03PM +0100, Philipp Zabel wrote:
> From: Philipp Zabel <philipp.zabel@gmail.com>
>
> The existing v4l2-of parser functions for the video interface bindings
> described in Documentation/device-tree/bindings/media/video-interfaces.txt
> are useful for DRM drivers, too. They will be moved to drivers/media
> so they can be used by drm drivers, too. Until then, duplicate the
> v4l2-of parser functions temporarily.
>
> Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Ergh. So, because we can't get agreement on where to put the common
helpers, we have to put up with adding duplicate helpers into the
staging directory, inflating not only the kernel source code size
but also the binary size as well.
Come on people, get agreement on how to deal with this. Staging may
be a dumping ground for drivers which aren't ready to be merged as
proper drivers, but this is no reason to ignore proper process.
Do we, or do we not want to get imx-drm out of drivers/staging? If
we do, the only way that's going to happen is if we stop throwing in
this kind of stuff.
--
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
^ permalink raw reply
* Re: [PATCHv1 5/6] HSI: Introduce OMAP SSI driver
From: Mark Rutland @ 2014-02-24 15:51 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Sebastian Reichel, Linus Walleij, Shubhrajyoti Datta,
Carlos Chinea, Tony Lindgren,
grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org, Pawel Moll,
Stephen Warren, Ian Campbell, Rob Landley,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Pali Rohár,
Ивайло Димитров,
Joni Lapilainen, Aaro Koskinen
In-Reply-To: <1393199401-27197-6-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
On Sun, Feb 23, 2014 at 11:50:00PM +0000, Sebastian Reichel wrote:
> Add OMAP SSI driver to the HSI subsystem.
>
> The Synchronous Serial Interface (SSI) is a legacy version
> of HSI. As in the case of HSI, it is mainly used to connect
> Application engines (APE) with cellular modem engines (CMT)
> in cellular handsets.
>
> It provides a multichannel, full-duplex, multi-core communication
> with no reference clock. The OMAP SSI block is capable of reaching
> speeds of 110 Mbit/s.
>
> Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> ---
> drivers/hsi/Kconfig | 1 +
> drivers/hsi/Makefile | 1 +
> drivers/hsi/controllers/Kconfig | 19 +
> drivers/hsi/controllers/Makefile | 6 +
> drivers/hsi/controllers/omap_ssi.c | 618 ++++++++++++++
> drivers/hsi/controllers/omap_ssi.h | 166 ++++
> drivers/hsi/controllers/omap_ssi_port.c | 1401 +++++++++++++++++++++++++++++++
> drivers/hsi/controllers/omap_ssi_regs.h | 171 ++++
> 8 files changed, 2383 insertions(+)
> create mode 100644 drivers/hsi/controllers/Kconfig
> create mode 100644 drivers/hsi/controllers/Makefile
> create mode 100644 drivers/hsi/controllers/omap_ssi.c
> create mode 100644 drivers/hsi/controllers/omap_ssi.h
> create mode 100644 drivers/hsi/controllers/omap_ssi_port.c
> create mode 100644 drivers/hsi/controllers/omap_ssi_regs.h
[...]
> + irq = platform_get_resource_byname(pd, IORESOURCE_IRQ, "gdd_mpu");
> + if (!irq) {
> + dev_err(&pd->dev, "GDD IRQ resource missing\n");
> + err = -ENXIO;
> + goto out_err;
> + }
> + omap_ssi->gdd_irq = irq->start;
You can use platform_get_irq_byname here.
[...]
> +static inline int ssi_of_get_available_child_count(const struct device_node *np)
> +{
> + struct device_node *child;
> + int num = 0;
> +
> + for_each_child_of_node(np, child)
> + if (of_device_is_available(child))
> + num++;
> +
> + return num;
> +}
You can find of_get_available_child_count in <linux/of.h>.
That said, this seems to be trying to count the numbero f ports, which
should all be compatible with "ti,omap3-ssi-port", no?
So maybe you should count all available child nodes compatible with
that.
> +
> +static int __init ssi_probe(struct platform_device *pd)
> +{
> + struct device_node *np = pd->dev.of_node;
> + struct hsi_controller *ssi;
> + int err;
> + int num_ports;
> +
> + if (!np) {
> + dev_err(&pd->dev, "missing device tree data\n");
> + return -EINVAL;
> + }
> +
> + num_ports = ssi_of_get_available_child_count(np);
> +
> + ssi = hsi_alloc_controller(num_ports, GFP_KERNEL);
> + if (!ssi) {
> + dev_err(&pd->dev, "No memory for controller\n");
> + return -ENOMEM;
> + }
> +
> + platform_set_drvdata(pd, ssi);
> +
> + err = ssi_add_controller(ssi, pd);
> + if (err < 0)
> + goto out1;
> +
> + pm_runtime_irq_safe(&pd->dev);
> + pm_runtime_enable(&pd->dev);
> +
> + err = ssi_hw_init(ssi);
> + if (err < 0)
> + goto out2;
> +#ifdef CONFIG_DEBUG_FS
> + err = ssi_debug_add_ctrl(ssi);
> + if (err < 0)
> + goto out2;
> +#endif
> +
> + err = of_platform_populate(pd->dev.of_node, NULL, NULL, &pd->dev);
I'm not keen on doing this because it allows arbitrary devices which are
not ssi ports to be placed in the ssi host controller node that will be
probed, which is nonsensical and something I'd like to avoid by
construction.
Is there any reason the ports have to be platform devices at all?
If so, is there no way we can register them directly and skip any other
devices?
[...]
> +static int __exit ssi_remove(struct platform_device *pd)
> +{
> + struct hsi_controller *ssi = platform_get_drvdata(pd);
> +
> +#ifdef CONFIG_DEBUG_FS
> + ssi_debug_remove_ctrl(ssi);
> +#endif
> + ssi_remove_controller(ssi);
> + platform_set_drvdata(pd, NULL);
> +
> + pm_runtime_disable(&pd->dev);
> +
> + /* cleanup of of_platform_populate() call */
> + device_for_each_child(&pd->dev, NULL, ssi_remove_ports);
This would certainly be broken for a non ssi port device.
[...]
> +static int omap_ssi_port_runtime_suspend(struct device *dev)
> +{
> + struct hsi_port *port = dev_get_drvdata(dev);
> + struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
> + struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
> + struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
> +
> + dev_dbg(dev, "port runtime suspend!\n");
> +
> + ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);
> + if (omap_ssi->get_loss)
> + omap_port->loss_count =
> + (*omap_ssi->get_loss)(ssi->device.parent);
You don't need to do (*struct->func)(args) when invoking a function
pointer. You can jsut have struct->func(args) as we do elsewhere. This
can be:
omap_ssi->get_loss(ssi->device.parent)
This should be fixed up in the other sites too.
Cheers,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] usb: dwc3: core: continue probing if usb phy library returns -ENODEV/-ENXIO
From: Felipe Balbi @ 2014-02-24 15:49 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: Roger Quadros, Heikki Krogerus, Felipe Balbi, george.cherian,
devicetree, linux-doc, linux-kernel, linux-omap, linux-arm-kernel,
linux-usb
In-Reply-To: <530B1609.8030804@ti.com>
[-- Attachment #1: Type: text/plain, Size: 7258 bytes --]
On Mon, Feb 24, 2014 at 03:21:05PM +0530, Kishon Vijay Abraham I wrote:
> Hi Roger,
>
> On Friday 21 February 2014 05:59 PM, Roger Quadros wrote:
> > On 02/21/2014 02:25 PM, Kishon Vijay Abraham I wrote:
> >> Hi Roger,
> >>
> >> On Wednesday 19 February 2014 06:07 PM, Roger Quadros wrote:
> >>> Hi,
> >>>
> >>> On 02/12/2014 11:46 AM, Kishon Vijay Abraham I wrote:
> >>>> On Wednesday 29 January 2014 08:17 PM, Heikki Krogerus wrote:
> >>>>> Hi,
> >>>>>
> >>>>> On Tue, Jan 28, 2014 at 10:30:36AM -0600, Felipe Balbi wrote:
> >>>>>> On Tue, Jan 28, 2014 at 05:32:30PM +0200, Heikki Krogerus wrote:
> >>>>>>> On Mon, Jan 27, 2014 at 10:05:20AM -0600, Felipe Balbi wrote:
> >>>>>>> For the controller drivers the PHYs are just a resource like any
> >>>>>>> other. The controller drivers can't have any responsibility of
> >>>>>>> them. They should not care if PHY drivers are available for them or
> >>>>>>> not, or even if the PHY framework is available or not.
> >>>>>>
> >>>>>> huh? If memory isn't available you don't continue probing, right ? If
> >>>>>> your IORESOURCE_MEM is missing, you also don't continue probing, if your
> >>>>>> IRQ line is missing, you bail too. Those are also nothing but resources
> >>>>>> to the driver, what you're asking here is to treat PHY as a _different_
> >>>>>> resource; which might be fine, but we need to make sure we don't
> >>>>>> continue probing when a PHY is missing in a platform that certainly
> >>>>>> needs a PHY.
> >>>>>
> >>>>> Yes, true. In my head I was comparing the PHY only to resources like
> >>>>> gpios, clocks, dma channels, etc. that are often optional to the
> >>>>> drivers.
> >>>>>
> >>>>>>>>>> But I really want to see the argument against using no-op. As far as I
> >>>>>>>>>> could see, everybody needs a PHY driver one way or another, some
> >>>>>>>>>> platforms just haven't sent any PHY driver upstream and have their own
> >>>>>>>>>> hacked up solution to avoid using the PHY layer.
> >>>>>>>>>
> >>>>>>>>> Not true in our case. Platforms using Intel's SoCs and chip sets may
> >>>>>>>>> or may not have controllable USB PHY. Quite often they don't. The
> >>>>>>>>> Baytrails have usually ULPI PHY for USB2, but that does not mean they
> >>>>>>>>> provide any vendor specific functions or any need for a driver in any
> >>>>>>>>> case.
> >>>>>>>>
> >>>>>>>> that's different from what I heard.
> >>>>>>>
> >>>>>>> I don't know where you got that impression, but it's not true. The
> >>>>>>> Baytrail SoCs for example don't have internal USB PHYs, which means
> >>>>>>> the manufacturers using it can select what they want. So we have
> >>>>>>> boards where PHY driver(s) is needed and boards where it isn't.
> >>>>>>
> >>>>>> alright, that explains it ;-) So you have external USB2 and USB3 PHYs ?
> >>>>>> You have an external PIPE3 interface ? That's quite an achievement,
> >>>>>> kudos to your HW designers. Getting timing closure on PIPE3 is a
> >>>>>> difficult task.
> >>>>>
> >>>>> No, only the USB2 PHY is external. I'm giving you wrong information,
> >>>>> I'm sorry about that. Need to concentrate on what I'm writing.
> >>>>>
> >>>>> <snip>
> >>>>>
> >>>>>>> This is really good to get. We have some projects where we are dealing
> >>>>>>> with more embedded environments, like IVI, where the kernel should be
> >>>>>>> stripped of everything useless. Since the PHYs are autonomous, we
> >>>>>>> should be able to disable the PHY libraries/frameworks.
> >>>>>>
> >>>>>> hmmm, in that case it's a lot easier to treat. We can use
> >>>>>> ERR_PTR(-ENXIO) as an indication that the framework is disabled, or
> >>>>>> something like that.
> >>>>>>
> >>>>>> The difficult is really reliably supporting e.g. OMAP5 (which won't work
> >>>>>> without a PHY) and your BayTrail with autonomous PHYs. What can we use
> >>>>>> as an indication ?
> >>>>>
> >>>>> OMAP has it's own glue driver, so shouldn't it depend on the PHY
> >>>>> layer?
> >>>>
> >>>> right, but the PHY is connected to the dwc3 core and not to the glue.
> >>>>>
> >>>>>> I mean, I need to know that a particular platform depends on a PHY
> >>>>>> driver before I decide to return -EPROBE_DEFER or just assume the PHY
> >>>>>> isn't needed ;-)
> >>>>>
> >>>>> I don't think dwc3 (core) should care about that. The PHY layer needs
> >>>>> to tell us that. If the PHY driver that the platform depends is not
> >>>>> available yet, the PHY layer returns -EPROBE_DEFER and dwc3 ends up
> >>>>> returning -EPROBE_DEFER.
> >>>>
> >>>> I don't think the PHY layer can 'reliably' tell if PHY driver is available or
> >>>> not. Consider when the phy_provider_register fails, there is no way to know if
> >>>> PHY driver is available or not. There are a few cases where PHY layer returns
> >>>> -EPROBE_DEFER but none of them can tell for sure that PHY driver is either
> >>>> available and failed or not available at all. It would be best for us to leave
> >>>> that to the platforms if we want to be sure if the platform needs a PHY or not.
> >>>>
> >>>
> >>> Just to summarize this thread on what we need
> >>
> >> Thanks for summarizing.
> >>>
> >>> 1) dwc3 core shouldn't worry about platform specific stuff i.e.
> >>> PHY needed or not. It should be as generic as possible.
> >>>
> >>> 2) dwc3 core should continue probe even if PHY layer is not
> >>> enabled, as not all platforms need it.
> >>>
> >>> 3) dwc3 core should continue probe if PHY device is not available.
> >>> (-ENODEV?)
> >>>
> >>> 4) dwc3 core should error out on any error condition if PHY device
> >>> is available and caused some error, e.g. init error.
> >>>
> >>> 5) dwc3 core should return EPROBE_DEFER if PHY device is available
> >>> but device driver is not yet loaded.
> >>>
> >>> 6) platform glue should do the necessary sanity checks for
> >>> availability of all resources like PHY device, PHY layer, etc,
> >>> before populating the dwc3 device. e.g. in OMAP5 case we could
> >>> check if both usb2 and usb3 PHY nodes are available in the DT and
> >>> PHY layer is enabled, from dwc3-omap.c? In J6 case we could check
> >>> that at least usb2 phy node is there for the High-Speed only
> >>> controller, and so on.
> >>
> >> The PHY is connected to the dwc3 core. So I'm not sure if we should
> >> be doing checks for PHY in the glue layer.
> >
> > Sorry, I didn't get you. My reasoning was that since OMAP platform
> > has this strict requirement of requiring explicit PHY control in
> > order to work, we must do the sanity checks in OMAP specific code
> > and not in the dwc3 core code. It has nothing to do with how
> > hardware is laid out.
>
> What kind of sanity check do you think can be done in OMAP code? We don't use
> any of the PHY API's in glue code. If we add the same PHY APIs in glue code it
> will be duplication of the same code without much value besides breaking the
> design guideline of the software to be modelled similar to hardware.
>
> However in Kconfig of dwc3 glue we can add 'select GENERIC_PHY, select
> PHY_OMAP_USB2, select OMAP_USB3' I guess.
ick, please don't. We have suffered too much from selects being
sprinkled all over the place.
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [RFC PATCH v3 1/9] staging: imx-drm-core: don't request probe deferral in imx_drm_encoder_parse_of
From: Russell King - ARM Linux @ 2014-02-24 15:49 UTC (permalink / raw)
To: Philipp Zabel
Cc: devel, devicetree, David Airlie, Greg Kroah-Hartman, dri-devel,
kernel, Grant Likely, Shawn Guo, linux-arm-kernel, Lucas Stach
In-Reply-To: <1392723370-4772-2-git-send-email-p.zabel@pengutronix.de>
On Tue, Feb 18, 2014 at 12:36:02PM +0100, Philipp Zabel wrote:
> From: Lucas Stach <l.stach@pengutronix.de>
>
> Since imx_drm_encoder_parse_of is called from the encoder bind callbacks,
> it is too late to request probe deferral. Rather the core should make sure
> that the crtcs are bound before the encoders, after all needed components
> are probed.
Why is it too late? -EPROBE_DEFER from this point will cause the driver
initialisation to correctly unwind and return -EPROBE_DEFER to the
last-to-be-added component.
> This fixes probe failure when using the LDB on i.MX6.
More details please.
--
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox