[alsa-devel] [PATCH RFC 0/7] HDMI audio support for Exynos Odroid boards
In this series I gathered patches touching various subsystems to make the overall review easier, finally I'm going to post independently patches for each subsystem and the dts patch(es) will be postponed to subsequent merge window.
The main purpose of this series is to add audio codec interface to the Exynos DRM driver, so HDMI audio can be properly supported, also on boards where HDMI is the only connector available for audio.
Currently in mainline the ASoC simple-card is used for Odroid XU3, I decided to change it and use a dedicated ASoC machine driver, which allowed to implemement specific clock settings (EPLL and the I2S root clock adjusted to audio sample rates) and to ensure proper number of audio channels gets negotiated in multicodec system configuration.
This series is based on v4.11-rc6, has been tested on Odroid XU3.
Sylwester Nawrocki (7): clk: samsung: Add enable/disable operation for PLL36XX clocks clk: samsung: Add definitions of some audio related clocks clk: samsung: exynos542x: Add EPLL rate table drm: exynos: Add driver for HDMI audio interface ASoC: Add Odroid sound DT bindings documentation ASoC: samsung: Add Odroid ASoC machine driver ARM: dts: samsung: Switch to dedicated Odroid sound card binding
.../devicetree/bindings/sound/samsung,odroid.txt | 57 ++++++ arch/arm/boot/dts/exynos4.dtsi | 1 + arch/arm/boot/dts/exynos5420.dtsi | 1 + arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi | 59 ++++-- drivers/clk/samsung/clk-exynos5420.c | 31 ++- drivers/clk/samsung/clk-pll.c | 85 ++++---- drivers/gpu/drm/exynos/Kconfig | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 220 +++++++++++++++++---- include/dt-bindings/clock/exynos5420.h | 3 + sound/soc/samsung/Kconfig | 8 + sound/soc/samsung/Makefile | 2 + sound/soc/samsung/odroid.c | 219 ++++++++++++++++++++ 12 files changed, 599 insertions(+), 88 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/samsung,odroid.txt create mode 100644 sound/soc/samsung/odroid.c
The existing enable/disable ops for PLL35XX are made more generic and used also for PLL36XX. This fixes issues in the kernel with PLL36XX PLLs when the PLL has not been already enabled by bootloader.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- drivers/clk/samsung/clk-pll.c | 85 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-)
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 5229089..10c76eb 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -23,6 +23,10 @@ struct samsung_clk_pll { struct clk_hw hw; void __iomem *lock_reg; void __iomem *con_reg; + /* PLL enable control bit offset in @con_reg register */ + unsigned short enable_offs; + /* PLL lock status bit offset in @con_reg register */ + unsigned short lock_offs; enum samsung_pll_type type; unsigned int rate_count; const struct samsung_pll_rate_table *rate_table; @@ -61,6 +65,34 @@ static long samsung_pll_round_rate(struct clk_hw *hw, return rate_table[i - 1].rate; }
+static int samsung_pll3xxx_enable(struct clk_hw *hw) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 tmp; + + tmp = readl_relaxed(pll->con_reg); + tmp |= BIT(pll->enable_offs); + writel_relaxed(tmp, pll->con_reg); + + /* wait lock time */ + do { + cpu_relax(); + tmp = readl_relaxed(pll->con_reg); + } while (!(tmp & BIT(pll->lock_offs))); + + return 0; +} + +static void samsung_pll3xxx_disable(struct clk_hw *hw) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 tmp; + + tmp = readl_relaxed(pll->con_reg); + tmp |= BIT(pll->enable_offs); + writel_relaxed(tmp, pll->con_reg); +} + /* * PLL2126 Clock Type */ @@ -142,34 +174,6 @@ static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw, #define PLL35XX_LOCK_STAT_SHIFT (29) #define PLL35XX_ENABLE_SHIFT (31)
-static int samsung_pll35xx_enable(struct clk_hw *hw) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 tmp; - - tmp = readl_relaxed(pll->con_reg); - tmp |= BIT(PLL35XX_ENABLE_SHIFT); - writel_relaxed(tmp, pll->con_reg); - - /* wait_lock_time */ - do { - cpu_relax(); - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & BIT(PLL35XX_LOCK_STAT_SHIFT))); - - return 0; -} - -static void samsung_pll35xx_disable(struct clk_hw *hw) -{ - struct samsung_clk_pll *pll = to_clk_pll(hw); - u32 tmp; - - tmp = readl_relaxed(pll->con_reg); - tmp &= ~BIT(PLL35XX_ENABLE_SHIFT); - writel_relaxed(tmp, pll->con_reg); -} - static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -239,11 +243,11 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(tmp, pll->con_reg);
/* wait_lock_time if enabled */ - if (tmp & BIT(PLL35XX_ENABLE_SHIFT)) { + if (tmp & BIT(pll->enable_offs)) { do { cpu_relax(); tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & BIT(PLL35XX_LOCK_STAT_SHIFT))); + } while (!(tmp & BIT(pll->lock_offs))); } return 0; } @@ -252,8 +256,8 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, .recalc_rate = samsung_pll35xx_recalc_rate, .round_rate = samsung_pll_round_rate, .set_rate = samsung_pll35xx_set_rate, - .enable = samsung_pll35xx_enable, - .disable = samsung_pll35xx_disable, + .enable = samsung_pll3xxx_enable, + .disable = samsung_pll3xxx_disable, };
static const struct clk_ops samsung_pll35xx_clk_min_ops = { @@ -275,6 +279,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, #define PLL36XX_SDIV_SHIFT (0) #define PLL36XX_KDIV_SHIFT (0) #define PLL36XX_LOCK_STAT_SHIFT (29) +#define PLL36XX_ENABLE_SHIFT (31)
static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -354,10 +359,12 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(pll_con1, pll->con_reg + 4);
/* wait_lock_time */ - do { - cpu_relax(); - tmp = readl_relaxed(pll->con_reg); - } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT))); + if (pll_con0 & BIT(pll->enable_offs)) { + do { + cpu_relax(); + tmp = readl_relaxed(pll->con_reg); + } while (!(tmp & BIT(PLL36XX_LOCK_STAT_SHIFT))); + }
return 0; } @@ -366,6 +373,8 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, .recalc_rate = samsung_pll36xx_recalc_rate, .set_rate = samsung_pll36xx_set_rate, .round_rate = samsung_pll_round_rate, + .enable = samsung_pll3xxx_enable, + .disable = samsung_pll3xxx_disable, };
static const struct clk_ops samsung_pll36xx_clk_min_ops = { @@ -1288,6 +1297,8 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, case pll_1450x: case pll_1451x: case pll_1452x: + pll->enable_offs = PLL35XX_ENABLE_SHIFT; + pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT; if (!pll->rate_table) init.ops = &samsung_pll35xx_clk_min_ops; else @@ -1306,6 +1317,8 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, /* clk_ops for 36xx and 2650 are similar */ case pll_36xx: case pll_2650: + pll->enable_offs = PLL36XX_ENABLE_SHIFT; + pll->lock_offs = PLL36XX_LOCK_STAT_SHIFT; if (!pll->rate_table) init.ops = &samsung_pll36xx_clk_min_ops; else
On 04/21, Sylwester Nawrocki wrote:
The existing enable/disable ops for PLL35XX are made more generic and used also for PLL36XX. This fixes issues in the kernel with PLL36XX PLLs when the PLL has not been already enabled by bootloader.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
drivers/clk/samsung/clk-pll.c | 85 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-)
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 5229089..10c76eb 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -23,6 +23,10 @@ struct samsung_clk_pll { struct clk_hw hw; void __iomem *lock_reg; void __iomem *con_reg;
- /* PLL enable control bit offset in @con_reg register */
- unsigned short enable_offs;
- /* PLL lock status bit offset in @con_reg register */
- unsigned short lock_offs; enum samsung_pll_type type; unsigned int rate_count; const struct samsung_pll_rate_table *rate_table;
@@ -61,6 +65,34 @@ static long samsung_pll_round_rate(struct clk_hw *hw, return rate_table[i - 1].rate; }
+static int samsung_pll3xxx_enable(struct clk_hw *hw) +{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp |= BIT(pll->enable_offs);
- writel_relaxed(tmp, pll->con_reg);
- /* wait lock time */
- do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
- } while (!(tmp & BIT(pll->lock_offs)));
Not a problem with this patch because we're moving code around, but this is a potential infinite loop that should have some sort of timeout so we don't sit here forever trying to see a bit toggle.
On 04/22/2017 04:51 AM, Stephen Boyd wrote:
+static int samsung_pll3xxx_enable(struct clk_hw *hw) +{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp |= BIT(pll->enable_offs);
- writel_relaxed(tmp, pll->con_reg);
- /* wait lock time */
- do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
- } while (!(tmp & BIT(pll->lock_offs)));
Not a problem with this patch because we're moving code around, but this is a potential infinite loop that should have some sort of timeout so we don't sit here forever trying to see a bit toggle.
Yes, I will add some protection in new patch, like it is done for newer PLLs. Thanks for you review.
On Fri, Apr 21, 2017 at 07:19:45PM +0200, Sylwester Nawrocki wrote:
The existing enable/disable ops for PLL35XX are made more generic and used also for PLL36XX. This fixes issues in the kernel with PLL36XX PLLs when the PLL has not been already enabled by bootloader.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
drivers/clk/samsung/clk-pll.c | 85 +++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-)
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 5229089..10c76eb 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -23,6 +23,10 @@ struct samsung_clk_pll { struct clk_hw hw; void __iomem *lock_reg; void __iomem *con_reg;
- /* PLL enable control bit offset in @con_reg register */
- unsigned short enable_offs;
- /* PLL lock status bit offset in @con_reg register */
- unsigned short lock_offs; enum samsung_pll_type type; unsigned int rate_count; const struct samsung_pll_rate_table *rate_table;
@@ -61,6 +65,34 @@ static long samsung_pll_round_rate(struct clk_hw *hw, return rate_table[i - 1].rate; }
+static int samsung_pll3xxx_enable(struct clk_hw *hw) +{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp |= BIT(pll->enable_offs);
- writel_relaxed(tmp, pll->con_reg);
- /* wait lock time */
- do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
- } while (!(tmp & BIT(pll->lock_offs)));
- return 0;
+}
+static void samsung_pll3xxx_disable(struct clk_hw *hw) +{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp |= BIT(pll->enable_offs);
I think you meant here: tmp &= ~BIT()
- writel_relaxed(tmp, pll->con_reg);
+}
/*
- PLL2126 Clock Type
*/ @@ -142,34 +174,6 @@ static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw, #define PLL35XX_LOCK_STAT_SHIFT (29) #define PLL35XX_ENABLE_SHIFT (31)
-static int samsung_pll35xx_enable(struct clk_hw *hw) -{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp |= BIT(PLL35XX_ENABLE_SHIFT);
- writel_relaxed(tmp, pll->con_reg);
- /* wait_lock_time */
- do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
- } while (!(tmp & BIT(PLL35XX_LOCK_STAT_SHIFT)));
- return 0;
-}
-static void samsung_pll35xx_disable(struct clk_hw *hw) -{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp &= ~BIT(PLL35XX_ENABLE_SHIFT);
- writel_relaxed(tmp, pll->con_reg);
-}
static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -239,11 +243,11 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(tmp, pll->con_reg);
/* wait_lock_time if enabled */
- if (tmp & BIT(PLL35XX_ENABLE_SHIFT)) {
- if (tmp & BIT(pll->enable_offs)) { do { cpu_relax(); tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & BIT(PLL35XX_LOCK_STAT_SHIFT)));
} return 0;} while (!(tmp & BIT(pll->lock_offs)));
} @@ -252,8 +256,8 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, .recalc_rate = samsung_pll35xx_recalc_rate, .round_rate = samsung_pll_round_rate, .set_rate = samsung_pll35xx_set_rate,
- .enable = samsung_pll35xx_enable,
- .disable = samsung_pll35xx_disable,
- .enable = samsung_pll3xxx_enable,
- .disable = samsung_pll3xxx_disable,
};
static const struct clk_ops samsung_pll35xx_clk_min_ops = { @@ -275,6 +279,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate, #define PLL36XX_SDIV_SHIFT (0) #define PLL36XX_KDIV_SHIFT (0) #define PLL36XX_LOCK_STAT_SHIFT (29) +#define PLL36XX_ENABLE_SHIFT (31)
static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -354,10 +359,12 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(pll_con1, pll->con_reg + 4);
/* wait_lock_time */
- do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
- } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
- if (pll_con0 & BIT(pll->enable_offs)) {
Why this additional if() is needed?
do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & BIT(PLL36XX_LOCK_STAT_SHIFT)));
To be consistent: BIT(pll->lock_offs)?
Best regards, Krzysztof
On 04/22/2017 05:22 PM, Krzysztof Kozlowski wrote: [...]
+static void samsung_pll3xxx_disable(struct clk_hw *hw) +{
- struct samsung_clk_pll *pll = to_clk_pll(hw);
- u32 tmp;
- tmp = readl_relaxed(pll->con_reg);
- tmp |= BIT(pll->enable_offs);
I think you meant here: tmp &= ~BIT()
Yes, I messed it up while copy/pasting from samsung_pll3xxx_enable().
- writel_relaxed(tmp, pll->con_reg);
+}
static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -354,10 +359,12 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(pll_con1, pll->con_reg + 4);
/* wait_lock_time */
- do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
- } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
I will add a comment here like: /* Wait until the PLL is locked if it is enabled. */
- if (pll_con0 & BIT(pll->enable_offs)) {
Why this additional if() is needed?
The PLL will never transition to a locked state if it is disabled, without this test we would end up with an indefinite loop below.
do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & BIT(PLL36XX_LOCK_STAT_SHIFT)));
To be consistent: BIT(pll->lock_offs)?
Yes, fixed.
Thanks for your review!
-- Regards, Sylwester
On Mon, Apr 24, 2017 at 1:12 PM, Sylwester Nawrocki s.nawrocki@samsung.com wrote:
On 04/22/2017 05:22 PM, Krzysztof Kozlowski wrote:
@@ -354,10 +359,12 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(pll_con1, pll->con_reg + 4);
/* wait_lock_time */
do {
cpu_relax();
tmp = readl_relaxed(pll->con_reg);
} while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
I will add a comment here like: /* Wait until the PLL is locked if it is enabled. */
if (pll_con0 & BIT(pll->enable_offs)) {
Why this additional if() is needed?
The PLL will never transition to a locked state if it is disabled, without this test we would end up with an indefinite loop below.
Hmmm... shouldn't this be split from this change? Or maybe this is needed only because you added enable/disable for pl36xx and previously this was not existing?
Best regards, Krzysztof
This patch adds missing definitions of mux clocks required for using EPLL as the audio subsystem root clock on exynos5420/exynos5422 SoCs.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- drivers/clk/samsung/clk-exynos5420.c | 13 ++++++++----- include/dt-bindings/clock/exynos5420.h | 3 +++ 2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index cdc092a..87c711a 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -477,8 +477,7 @@ static void __init exynos5420_clk_sleep_init(void) {} "mout_sclk_mpll", "ff_dout_spll2", "mout_sclk_spll", "mout_sclk_epll"}; PNAME(mout_mau_epll_clk_5800_p) = { "mout_sclk_epll", "mout_sclk_dpll", - "mout_sclk_mpll", - "ff_dout_spll2" }; + "mout_sclk_mpll", "ff_dout_spll2" }; PNAME(mout_group8_5800_p) = { "dout_aclk432_scaler", "dout_sclk_sw" }; PNAME(mout_group9_5800_p) = { "dout_osc_div", "mout_sw_aclk432_scaler" }; PNAME(mout_group10_5800_p) = { "dout_aclk432_cam", "dout_sclk_sw" }; @@ -487,6 +486,7 @@ static void __init exynos5420_clk_sleep_init(void) {} PNAME(mout_group13_5800_p) = { "dout_osc_div", "mout_sw_aclkfl1_550_cam" }; PNAME(mout_group14_5800_p) = { "dout_aclk550_cam", "dout_sclk_sw" }; PNAME(mout_group15_5800_p) = { "dout_osc_div", "mout_sw_aclk550_cam" }; +PNAME(mout_group16_5800_p) = { "dout_osc_div", "mout_mau_epll_clk" };
/* fixed rate clocks generated outside the soc */ static struct samsung_fixed_rate_clock @@ -536,8 +536,8 @@ static void __init exynos5420_clk_sleep_init(void) {}
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2), - MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, SRC_TOP7, - 20, 2), + MUX(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, + SRC_TOP7, 20, 2), MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1), MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1),
@@ -546,6 +546,8 @@ static void __init exynos5420_clk_sleep_init(void) {} MUX(0, "mout_aclk432_cam", mout_group6_5800_p, SRC_TOP8, 24, 2), MUX(0, "mout_aclk432_scaler", mout_group6_5800_p, SRC_TOP8, 28, 2),
+ MUX(CLK_MOUT_USER_MAU_EPLL, "mout_user_mau_epll", mout_group16_5800_p, + SRC_TOP9, 8, 1), MUX(0, "mout_user_aclk550_cam", mout_group15_5800_p, SRC_TOP9, 16, 1), MUX(0, "mout_user_aclkfl1_550_cam", mout_group13_5800_p, @@ -703,7 +705,7 @@ static void __init exynos5420_clk_sleep_init(void) {} MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1), MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1), MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1), - MUX(0, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1), + MUX(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1), MUX(0, "mout_sclk_dpll", mout_dpll_p, SRC_TOP6, 24, 1), MUX(0, "mout_sclk_cpll", mout_cpll_p, SRC_TOP6, 28, 1),
@@ -1399,6 +1401,7 @@ static void __init exynos5x_clk_init(struct device_node *np,
if (_get_rate("fin_pll") == 24 * MHZ) { exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl; + exynos5x_plls[epll].rate_table = exynos5420_pll2550x_24mhz_tbl; exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl; exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl; } diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index 6fd21c2..2740ae0 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h @@ -217,6 +217,9 @@ #define CLK_MOUT_MCLK_CDREX 654 #define CLK_MOUT_BPLL 655 #define CLK_MOUT_MX_MSPLL_CCORE 656 +#define CLK_MOUT_EPLL 657 +#define CLK_MOUT_MAU_EPLL 658 +#define CLK_MOUT_USER_MAU_EPLL 659
/* divider clocks */ #define CLK_DOUT_PIXEL 768
On Fri, Apr 21, 2017 at 07:19:46PM +0200, Sylwester Nawrocki wrote:
This patch adds missing definitions of mux clocks required for using EPLL as the audio subsystem root clock on exynos5420/exynos5422 SoCs.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
drivers/clk/samsung/clk-exynos5420.c | 13 ++++++++----- include/dt-bindings/clock/exynos5420.h | 3 +++ 2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index cdc092a..87c711a 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -477,8 +477,7 @@ static void __init exynos5420_clk_sleep_init(void) {} "mout_sclk_mpll", "ff_dout_spll2", "mout_sclk_spll", "mout_sclk_epll"}; PNAME(mout_mau_epll_clk_5800_p) = { "mout_sclk_epll", "mout_sclk_dpll",
"mout_sclk_mpll",
"ff_dout_spll2" };
"mout_sclk_mpll", "ff_dout_spll2" };
Please split up cleaning from adding new features/clocks. While in cleaning mode, you might also consider fixing some checkpatch errors and warnings. There are few (without --strict).
PNAME(mout_group8_5800_p) = { "dout_aclk432_scaler", "dout_sclk_sw" }; PNAME(mout_group9_5800_p) = { "dout_osc_div", "mout_sw_aclk432_scaler" }; PNAME(mout_group10_5800_p) = { "dout_aclk432_cam", "dout_sclk_sw" }; @@ -487,6 +486,7 @@ static void __init exynos5420_clk_sleep_init(void) {} PNAME(mout_group13_5800_p) = { "dout_osc_div", "mout_sw_aclkfl1_550_cam" }; PNAME(mout_group14_5800_p) = { "dout_aclk550_cam", "dout_sclk_sw" }; PNAME(mout_group15_5800_p) = { "dout_osc_div", "mout_sw_aclk550_cam" }; +PNAME(mout_group16_5800_p) = { "dout_osc_div", "mout_mau_epll_clk" };
/* fixed rate clocks generated outside the soc */ static struct samsung_fixed_rate_clock @@ -536,8 +536,8 @@ static void __init exynos5420_clk_sleep_init(void) {}
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2),
- MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, SRC_TOP7,
20, 2),
- MUX(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p,
SRC_TOP7, 20, 2),
How about not changing the indention level of new line? On the other hand, if you want to change it so maybe align it with opening parenthesis?
(same in other places below)
Best regards, Krzysztof
A specific clock rate table is added for EPLL so it is possible to set frequency of the EPLL output clock as multiple of various audio sampling rates.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- drivers/clk/samsung/clk-exynos5420.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 87c711a..6fbd6ae 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1279,6 +1279,22 @@ static void __init exynos5420_clk_sleep_init(void) {} PLL_35XX_RATE(200000000, 200, 3, 3), };
+static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = { + PLL_36XX_RATE(600000000U, 100, 2, 1, 0), + PLL_36XX_RATE(400000000U, 200, 2, 2, 0), + PLL_36XX_RATE(393216000U, 197, 3, 2, 25690), + PLL_36XX_RATE(361267200U, 301, 5, 2, 3671), + PLL_36XX_RATE(200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(196608000U, 197, 3, 3, -25690), + PLL_36XX_RATE(180633600U, 301, 5, 3, 3671), + PLL_36XX_RATE(131072000U, 131, 3, 3, 4719), + PLL_36XX_RATE(100000000U, 200, 3, 4, 0), + PLL_36XX_RATE( 65536000U, 131, 3, 4, 4719), + PLL_36XX_RATE( 49152000U, 197, 3, 5, 25690), + PLL_36XX_RATE( 45158400U, 301, 5, 3, 3671), + PLL_36XX_RATE( 32768000U, 131, 3, 5, 4719), +}; + static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { [apll] = PLL(pll_2550, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK, APLL_CON0, NULL), @@ -1286,7 +1302,7 @@ static void __init exynos5420_clk_sleep_init(void) {} CPLL_CON0, NULL), [dpll] = PLL(pll_2550, CLK_FOUT_DPLL, "fout_dpll", "fin_pll", DPLL_LOCK, DPLL_CON0, NULL), - [epll] = PLL(pll_2650, CLK_FOUT_EPLL, "fout_epll", "fin_pll", EPLL_LOCK, + [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll", EPLL_LOCK, EPLL_CON0, NULL), [rpll] = PLL(pll_2650, CLK_FOUT_RPLL, "fout_rpll", "fin_pll", RPLL_LOCK, RPLL_CON0, NULL), @@ -1401,7 +1417,7 @@ static void __init exynos5x_clk_init(struct device_node *np,
if (_get_rate("fin_pll") == 24 * MHZ) { exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl; - exynos5x_plls[epll].rate_table = exynos5420_pll2550x_24mhz_tbl; + exynos5x_plls[epll].rate_table = exynos5420_epll_24mhz_tbl; exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl; exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl; }
On Fri, Apr 21, 2017 at 07:19:47PM +0200, Sylwester Nawrocki wrote:
A specific clock rate table is added for EPLL so it is possible to set frequency of the EPLL output clock as multiple of various audio sampling rates.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
drivers/clk/samsung/clk-exynos5420.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
Looks correct although I didn't check the numbers. Reviewed-by: Krzysztof Kozlowski krzk@kernel.org
Best regards, Krzysztof
The hdmi-codec interface added in this patch is required to properly support HDMI audio. Currently the audio part of the SoC internal HDMI transmitter is configured with fixed values, which makes HDMI audio working by chance, only on boards equipped with external audio codec connected in parallel with the HDMI audio transmitter I2S input interface.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- drivers/gpu/drm/exynos/Kconfig | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 220 +++++++++++++++++++++++++++++------ 2 files changed, 188 insertions(+), 33 deletions(-)
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 1d18534..a6edbb6 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -3,6 +3,7 @@ config DRM_EXYNOS depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM) select DRM_KMS_HELPER select VIDEOMODE_HELPERS + select SND_SOC_HDMI_CODEC if SND_SOC help Choose this option if you have a Samsung SoC EXYNOS chipset. If M is selected the module will be called exynosdrm. diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 88ccc04..be18023 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -40,7 +40,7 @@ #include <linux/component.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> - +#include <sound/hdmi-codec.h> #include <drm/exynos_drm.h>
#include "exynos_drm_drv.h" @@ -110,13 +110,23 @@ struct hdmi_driver_data { struct string_array_spec clk_muxes; };
+struct hdmi_audio { + struct platform_device *pdev; + struct hdmi_audio_infoframe infoframe; + unsigned int sample_rate; + unsigned int sample_width; + u8 enable; +}; + struct hdmi_context { struct drm_encoder encoder; struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; + struct hdmi_audio audio; bool powered; bool dvi_mode; + struct mutex mutex; struct delayed_work hotplug_work; struct drm_display_mode current_mode; const struct hdmi_driver_data *drv_data; @@ -766,6 +776,22 @@ static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy) return ret; }
+static int hdmi_audio_infoframe_apply(struct hdmi_context *hdata) +{ + struct hdmi_audio_infoframe *infoframe = &hdata->audio.infoframe; + u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + int len; + + len = hdmi_audio_infoframe_pack(infoframe, buf, sizeof(buf)); + if (len < 0) + return len; + + hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_EVERY_VSYNC); + hdmi_reg_write_buf(hdata, HDMI_AUI_HEADER0, buf, len); + + return 0; +} + static void hdmi_reg_infoframes(struct hdmi_context *hdata) { union hdmi_infoframe frm; @@ -803,15 +829,7 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) hdmi_reg_write_buf(hdata, HDMI_VSI_DATA(0), buf + 3, ret - 3); }
- ret = hdmi_audio_infoframe_init(&frm.audio); - if (!ret) { - frm.audio.channels = 2; - ret = hdmi_audio_infoframe_pack(&frm.audio, buf, sizeof(buf)); - } - if (ret > 0) { - hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_EVERY_VSYNC); - hdmi_reg_write_buf(hdata, HDMI_AUI_HEADER0, buf, ret); - } + hdmi_audio_infoframe_apply(hdata); }
static enum drm_connector_status hdmi_detect(struct drm_connector *connector, @@ -993,23 +1011,18 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq) hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); }
-static void hdmi_audio_init(struct hdmi_context *hdata) +static void hdmi_audio_config(struct hdmi_context *hdata) { - u32 sample_rate, bits_per_sample; - u32 data_num, bit_ch, sample_frq; - u32 val; + u32 data_num, sample_freq, val; + u32 bit_ch = 1;
- sample_rate = 44100; - bits_per_sample = 16;
- switch (bits_per_sample) { + switch (hdata->audio.sample_width) { case 20: data_num = 2; - bit_ch = 1; break; case 24: data_num = 3; - bit_ch = 1; break; default: data_num = 1; @@ -1017,7 +1030,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata) break; }
- hdmi_reg_acr(hdata, sample_rate); + hdmi_reg_acr(hdata, hdata->audio.sample_rate);
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE @@ -1028,10 +1041,21 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
- sample_frq = (sample_rate == 44100) ? 0 : - (sample_rate == 48000) ? 2 : - (sample_rate == 32000) ? 3 : - (sample_rate == 96000) ? 0xa : 0x0; + switch(hdata->audio.sample_rate) { + case 32000: + sample_freq = 0x3; + break; + case 48000: + sample_freq = 0x2; + break; + case 96000: + sample_freq = 0xa; + break; + case 44100: + default: + sample_freq = 0; + break; + }
hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS); hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN); @@ -1065,7 +1089,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER); hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0)); hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2 - | HDMI_I2S_SET_SMP_FREQ(sample_frq)); + | HDMI_I2S_SET_SMP_FREQ(sample_freq)); hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4, HDMI_I2S_ORG_SMP_FREQ_44_1 | HDMI_I2S_WORD_LEN_MAX24_24BITS @@ -1074,13 +1098,15 @@ static void hdmi_audio_init(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD); }
-static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff) +static void hdmi_audio_control(struct hdmi_context *hdata) { + bool enable = hdata->audio.enable; + if (hdata->dvi_mode) return;
- hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0); - hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ? + hdmi_reg_writeb(hdata, HDMI_AUI_CON, enable ? 2 : 0); + hdmi_reg_writemask(hdata, HDMI_CON_0, enable ? HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK); }
@@ -1400,9 +1426,9 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) { hdmi_start(hdata, false); hdmi_conf_init(hdata); - hdmi_audio_init(hdata); + hdmi_audio_config(hdata); hdmi_mode_apply(hdata); - hdmi_audio_control(hdata, true); + hdmi_audio_control(hdata); }
static void hdmi_mode_set(struct drm_encoder *encoder, @@ -1476,8 +1502,12 @@ static void hdmi_enable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder);
+ mutex_lock(&hdata->mutex); + hdmiphy_enable(hdata); hdmi_conf_apply(hdata); + + mutex_unlock(&hdata->mutex); }
static void hdmi_disable(struct drm_encoder *encoder) @@ -1486,6 +1516,8 @@ static void hdmi_disable(struct drm_encoder *encoder) struct drm_crtc *crtc = encoder->crtc; const struct drm_crtc_helper_funcs *funcs = NULL;
+ mutex_lock(&hdata->mutex); + if (!hdata->powered) return;
@@ -1506,6 +1538,8 @@ static void hdmi_disable(struct drm_encoder *encoder) cancel_delayed_work(&hdata->hotplug_work);
hdmiphy_disable(hdata); + + mutex_unlock(&hdata->mutex); }
static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { @@ -1519,6 +1553,109 @@ static void hdmi_disable(struct drm_encoder *encoder) .destroy = drm_encoder_cleanup, };
+static void hdmi_audio_shutdown(struct device *dev, void *data) +{ + struct hdmi_context *hdata = dev_get_drvdata(dev); + + mutex_lock(&hdata->mutex); + + hdata->audio.enable = false; + + if (hdata->powered) + hdmi_audio_control(hdata); + + mutex_unlock(&hdata->mutex); +} + +static int hdmi_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct hdmi_context *hdata = dev_get_drvdata(dev); + + if (daifmt->fmt != HDMI_I2S || daifmt->bit_clk_inv || + daifmt->frame_clk_inv || daifmt->bit_clk_master || + daifmt->frame_clk_master) { + dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, + daifmt->bit_clk_inv, daifmt->frame_clk_inv, + daifmt->bit_clk_master, + daifmt->frame_clk_master); + return -EINVAL; + } + + mutex_lock(&hdata->mutex); + + hdata->audio.sample_rate = params->sample_rate; + hdata->audio.sample_width = params->sample_width; + hdata->audio.infoframe = params->cea; + + if (hdata->powered) { + hdmi_audio_config(hdata); + hdmi_audio_infoframe_apply(hdata); + } + + mutex_unlock(&hdata->mutex); + + return 0; +} + +static int hdmi_audio_digital_mute(struct device *dev, void *data, bool mute) +{ + struct hdmi_context *hdata = dev_get_drvdata(dev); + + mutex_lock(&hdata->mutex); + + hdata->audio.enable = !mute; + + if (hdata->powered) + hdmi_audio_control(hdata); + + mutex_unlock(&hdata->mutex); + + return 0; +} + +static int hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf, + size_t len) +{ + struct hdmi_context *hdata = dev_get_drvdata(dev); + struct drm_connector *connector = &hdata->connector; + + memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); + + return 0; +} + +static const struct hdmi_codec_ops audio_codec_ops = { + .hw_params = hdmi_audio_hw_params, + .audio_shutdown = hdmi_audio_shutdown, + .digital_mute = hdmi_audio_digital_mute, + .get_eld = hdmi_audio_get_eld, +}; + +static int hdmi_register_audio_device(struct hdmi_context *hdata) +{ + struct hdmi_codec_pdata codec_data = { + .ops = &audio_codec_ops, + .max_i2s_channels = 6, + .i2s = 1, + }; + + hdata->audio.pdev = platform_device_register_data( + hdata->dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, + &codec_data, sizeof(codec_data)); + + if (IS_ERR(hdata->audio.pdev)) + return PTR_ERR(hdata->audio.pdev); + + return 0; +} + +static void hdmi_unregister_audio_device(struct hdmi_context *hdata) +{ + platform_device_unregister(hdata->audio.pdev); +} + static void hdmi_hotplug_work_func(struct work_struct *work) { struct hdmi_context *hdata; @@ -1703,6 +1840,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; struct hdmi_context *hdata = dev_get_drvdata(dev); struct drm_encoder *encoder = &hdata->encoder; + struct hdmi_audio_infoframe *audio_infoframe = &hdata->audio.infoframe; int ret, pipe;
hdata->drm_dev = drm_dev; @@ -1720,6 +1858,12 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+ hdmi_audio_infoframe_init(audio_infoframe); + audio_infoframe->coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; + audio_infoframe->sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; + audio_infoframe->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + audio_infoframe->channels = 2; + drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
@@ -1822,11 +1966,11 @@ static int hdmi_probe(struct platform_device *pdev) return -ENOMEM;
hdata->drv_data = of_device_get_match_data(dev); - platform_set_drvdata(pdev, hdata); - hdata->dev = dev;
+ mutex_init(&hdata->mutex); + ret = hdmi_resources_init(hdata); if (ret) { if (ret != -EPROBE_DEFER) @@ -1880,12 +2024,19 @@ static int hdmi_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
- ret = component_add(&pdev->dev, &hdmi_component_ops); + ret = hdmi_register_audio_device(hdata); if (ret) goto err_disable_pm_runtime;
+ ret = component_add(&pdev->dev, &hdmi_component_ops); + if (ret) + goto err_unregister_audio; + return ret;
+err_unregister_audio: + hdmi_unregister_audio_device(hdata); + err_disable_pm_runtime: pm_runtime_disable(dev);
@@ -1906,6 +2057,7 @@ static int hdmi_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&hdata->hotplug_work);
+ hdmi_unregister_audio_device(hdata); component_del(&pdev->dev, &hdmi_component_ops);
pm_runtime_disable(&pdev->dev); @@ -1921,6 +2073,8 @@ static int hdmi_remove(struct platform_device *pdev)
put_device(&hdata->ddc_adpt->dev);
+ mutex_destroy(&hdata->mutex); + return 0; }
On Fri, Apr 21, 2017 at 07:19:48PM +0200, Sylwester Nawrocki wrote:
The hdmi-codec interface added in this patch is required to properly support HDMI audio. Currently the audio part of the SoC internal HDMI transmitter is configured with fixed values, which makes HDMI audio working by chance, only on boards equipped with external audio codec connected in parallel with the HDMI audio transmitter I2S input interface.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
drivers/gpu/drm/exynos/Kconfig | 1 + drivers/gpu/drm/exynos/exynos_hdmi.c | 220 +++++++++++++++++++++++++++++------ 2 files changed, 188 insertions(+), 33 deletions(-)
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 1d18534..a6edbb6 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -3,6 +3,7 @@ config DRM_EXYNOS depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM) select DRM_KMS_HELPER select VIDEOMODE_HELPERS
- select SND_SOC_HDMI_CODEC if SND_SOC help Choose this option if you have a Samsung SoC EXYNOS chipset. If M is selected the module will be called exynosdrm.
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 88ccc04..be18023 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -40,7 +40,7 @@ #include <linux/component.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h>
+#include <sound/hdmi-codec.h> #include <drm/exynos_drm.h>
#include "exynos_drm_drv.h" @@ -110,13 +110,23 @@ struct hdmi_driver_data { struct string_array_spec clk_muxes; };
+struct hdmi_audio {
- struct platform_device *pdev;
- struct hdmi_audio_infoframe infoframe;
- unsigned int sample_rate;
- unsigned int sample_width;
- u8 enable;
+};
struct hdmi_context { struct drm_encoder encoder; struct device *dev; struct drm_device *drm_dev; struct drm_connector connector;
- struct hdmi_audio audio; bool powered; bool dvi_mode;
- struct mutex mutex;
I find short documentation what is protected by mutex usually quite useful. Can you add such?
struct delayed_work hotplug_work; struct drm_display_mode current_mode; const struct hdmi_driver_data *drv_data; @@ -766,6 +776,22 @@ static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy) return ret; }
+static int hdmi_audio_infoframe_apply(struct hdmi_context *hdata) +{
- struct hdmi_audio_infoframe *infoframe = &hdata->audio.infoframe;
- u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)];
- int len;
- len = hdmi_audio_infoframe_pack(infoframe, buf, sizeof(buf));
- if (len < 0)
return len;
- hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_EVERY_VSYNC);
- hdmi_reg_write_buf(hdata, HDMI_AUI_HEADER0, buf, len);
- return 0;
+}
static void hdmi_reg_infoframes(struct hdmi_context *hdata) { union hdmi_infoframe frm; @@ -803,15 +829,7 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata) hdmi_reg_write_buf(hdata, HDMI_VSI_DATA(0), buf + 3, ret - 3); }
- ret = hdmi_audio_infoframe_init(&frm.audio);
- if (!ret) {
frm.audio.channels = 2;
ret = hdmi_audio_infoframe_pack(&frm.audio, buf, sizeof(buf));
- }
- if (ret > 0) {
hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_EVERY_VSYNC);
hdmi_reg_write_buf(hdata, HDMI_AUI_HEADER0, buf, ret);
- }
- hdmi_audio_infoframe_apply(hdata);
}
static enum drm_connector_status hdmi_detect(struct drm_connector *connector, @@ -993,23 +1011,18 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq) hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4); }
-static void hdmi_audio_init(struct hdmi_context *hdata) +static void hdmi_audio_config(struct hdmi_context *hdata) {
- u32 sample_rate, bits_per_sample;
- u32 data_num, bit_ch, sample_frq;
- u32 val;
- u32 data_num, sample_freq, val;
- u32 bit_ch = 1;
sample_rate = 44100;
bits_per_sample = 16;
switch (bits_per_sample) {
- switch (hdata->audio.sample_width) { case 20: data_num = 2;
break; case 24: data_num = 3;bit_ch = 1;
break; default: data_num = 1;bit_ch = 1;
@@ -1017,7 +1030,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata) break; }
- hdmi_reg_acr(hdata, sample_rate);
hdmi_reg_acr(hdata, hdata->audio.sample_rate);
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
@@ -1028,10 +1041,21 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
- sample_frq = (sample_rate == 44100) ? 0 :
(sample_rate == 48000) ? 2 :
(sample_rate == 32000) ? 3 :
(sample_rate == 96000) ? 0xa : 0x0;
switch(hdata->audio.sample_rate) {
case 32000:
sample_freq = 0x3;
break;
case 48000:
sample_freq = 0x2;
break;
case 96000:
sample_freq = 0xa;
break;
case 44100:
default:
sample_freq = 0;
break;
}
hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS); hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
@@ -1065,7 +1089,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER); hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0)); hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
| HDMI_I2S_SET_SMP_FREQ(sample_frq));
hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4, HDMI_I2S_ORG_SMP_FREQ_44_1 | HDMI_I2S_WORD_LEN_MAX24_24BITS| HDMI_I2S_SET_SMP_FREQ(sample_freq));
@@ -1074,13 +1098,15 @@ static void hdmi_audio_init(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD); }
-static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff) +static void hdmi_audio_control(struct hdmi_context *hdata) {
- bool enable = hdata->audio.enable;
- if (hdata->dvi_mode) return;
- hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
- hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
- hdmi_reg_writeb(hdata, HDMI_AUI_CON, enable ? 2 : 0);
- hdmi_reg_writemask(hdata, HDMI_CON_0, enable ? HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
}
@@ -1400,9 +1426,9 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) { hdmi_start(hdata, false); hdmi_conf_init(hdata);
- hdmi_audio_init(hdata);
- hdmi_audio_config(hdata); hdmi_mode_apply(hdata);
- hdmi_audio_control(hdata, true);
- hdmi_audio_control(hdata);
}
static void hdmi_mode_set(struct drm_encoder *encoder, @@ -1476,8 +1502,12 @@ static void hdmi_enable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder);
- mutex_lock(&hdata->mutex);
- hdmiphy_enable(hdata); hdmi_conf_apply(hdata);
- mutex_unlock(&hdata->mutex);
}
static void hdmi_disable(struct drm_encoder *encoder) @@ -1486,6 +1516,8 @@ static void hdmi_disable(struct drm_encoder *encoder) struct drm_crtc *crtc = encoder->crtc; const struct drm_crtc_helper_funcs *funcs = NULL;
- mutex_lock(&hdata->mutex);
- if (!hdata->powered)
Need to unlock mutex (here and maybe in other exit paths?).
Best regards, Krzysztof
This patch adds DT binding documentation for Odroid XU3/4 sound subsystem.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- .../devicetree/bindings/sound/samsung,odroid.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/samsung,odroid.txt
diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.txt b/Documentation/devicetree/bindings/sound/samsung,odroid.txt new file mode 100644 index 0000000..c1ac70c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.txt @@ -0,0 +1,57 @@ +Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec + +Required properties: + + - compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board, + "samsung,odroidxu4-audio" - for Odroid XU4 board + - model - the user-visible name of this sound complex + - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S + controller + - 'codec' subnode with a 'sound-dai' property containing list of phandles + to the CODEC nodes, first entry must be corresponding to the MAX98090 + CODEC and the second entry must be the phandle of the HDMI IP block node + - clocks - should contain entries matching clock names in the clock-names + property + - clock-names - should contain following entries: + - "epll" - indicating the EPLL output clock + - "i2s_rclk" - indicating the RCLK (root) clock of the I2S0 controller + - samsung,audio-widgets - this property specifies off-codec audio elements + like headphones or speakers, for details see widgets.txt + - samsung,audio-routing - a list of the connections between audio + components; each entry is a pair of strings, the first being the + connection's sink, the second being the connection's source; + valid names for sources and sinks are the MAX98090's pins (as + documented in its binding), and the jacks on the board + + For Odroid X2: + "Headphone Jack", "Mic Jack", "DMIC" + + For Odroid U3, XU3: + "Headphone Jack", "Speakers" + + For Odroid XU4: + no entries + +Example: + +sound { + compatible = "samsung,odroidxu3-audio"; + samsung,cpu-dai = <&i2s0>; + samsung,codec-dai = <&max98090>; + model = "Odroid-XU3"; + samsung,audio-routing = + "Headphone Jack", "HPL", + "Headphone Jack", "HPR", + "IN1", "Mic Jack", + "Mic Jack", "MICBIAS"; + + clocks = <&clock CLK_FOUT_EPLL>, <&i2s0 CLK_I2S_RCLK_SRC>; + clock-names = "epll", "sclk_i2s"; + + cpu { + sound-dai = <&i2s0 0>; + }; + codec { + sound-dai = <&hdmi>, <&max98090>; + }; +};
The patch
ASoC: Add Odroid sound DT bindings documentation
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 92c9f05ebc7290e638c7b1b85288918c4fc65d4e Mon Sep 17 00:00:00 2001
From: Sylwester Nawrocki s.nawrocki@samsung.com Date: Fri, 21 Apr 2017 19:19:49 +0200 Subject: [PATCH] ASoC: Add Odroid sound DT bindings documentation
This patch adds DT binding documentation for Odroid XU3/4 sound subsystem.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com Signed-off-by: Mark Brown broonie@kernel.org --- .../devicetree/bindings/sound/samsung,odroid.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/samsung,odroid.txt
diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.txt b/Documentation/devicetree/bindings/sound/samsung,odroid.txt new file mode 100644 index 000000000000..c1ac70cb0afb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.txt @@ -0,0 +1,57 @@ +Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec + +Required properties: + + - compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board, + "samsung,odroidxu4-audio" - for Odroid XU4 board + - model - the user-visible name of this sound complex + - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S + controller + - 'codec' subnode with a 'sound-dai' property containing list of phandles + to the CODEC nodes, first entry must be corresponding to the MAX98090 + CODEC and the second entry must be the phandle of the HDMI IP block node + - clocks - should contain entries matching clock names in the clock-names + property + - clock-names - should contain following entries: + - "epll" - indicating the EPLL output clock + - "i2s_rclk" - indicating the RCLK (root) clock of the I2S0 controller + - samsung,audio-widgets - this property specifies off-codec audio elements + like headphones or speakers, for details see widgets.txt + - samsung,audio-routing - a list of the connections between audio + components; each entry is a pair of strings, the first being the + connection's sink, the second being the connection's source; + valid names for sources and sinks are the MAX98090's pins (as + documented in its binding), and the jacks on the board + + For Odroid X2: + "Headphone Jack", "Mic Jack", "DMIC" + + For Odroid U3, XU3: + "Headphone Jack", "Speakers" + + For Odroid XU4: + no entries + +Example: + +sound { + compatible = "samsung,odroidxu3-audio"; + samsung,cpu-dai = <&i2s0>; + samsung,codec-dai = <&max98090>; + model = "Odroid-XU3"; + samsung,audio-routing = + "Headphone Jack", "HPL", + "Headphone Jack", "HPR", + "IN1", "Mic Jack", + "Mic Jack", "MICBIAS"; + + clocks = <&clock CLK_FOUT_EPLL>, <&i2s0 CLK_I2S_RCLK_SRC>; + clock-names = "epll", "sclk_i2s"; + + cpu { + sound-dai = <&i2s0 0>; + }; + codec { + sound-dai = <&hdmi>, <&max98090>; + }; +};
On Fri, Apr 21, 2017 at 7:28 PM, Mark Brown broonie@kernel.org wrote:
The patch
ASoC: Add Odroid sound DT bindings documentation
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 92c9f05ebc7290e638c7b1b85288918c4fc65d4e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki s.nawrocki@samsung.com Date: Fri, 21 Apr 2017 19:19:49 +0200 Subject: [PATCH] ASoC: Add Odroid sound DT bindings documentation
This patch adds DT binding documentation for Odroid XU3/4 sound subsystem.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com Signed-off-by: Mark Brown broonie@kernel.org
.../devicetree/bindings/sound/samsung,odroid.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/samsung,odroid.txt
Hi Mark,
Although Sylwester is known of writing good quality code and can be trusted but he posted it just 9 minutes ago. Isn't it a little bit too fast to apply? I just finished reading cover letter but didn't manage to start looking at the rest. :)
Best regards, Krzysztof
On Fri, Apr 21, 2017 at 07:31:42PM +0200, Krzysztof Kozlowski wrote:
Although Sylwester is known of writing good quality code and can be trusted but he posted it just 9 minutes ago. Isn't it a little bit too fast to apply? I just finished reading cover letter but didn't manage to start looking at the rest. :)
It's pretty standard boilerplate stuff, there's not much in there to review and Sylwester is one of the maintainers listed for this code so I wasn't particularly expecting extra review.
On Fri, Apr 21, 2017 at 06:58:00PM +0100, Mark Brown wrote:
On Fri, Apr 21, 2017 at 07:31:42PM +0200, Krzysztof Kozlowski wrote:
Although Sylwester is known of writing good quality code and can be trusted but he posted it just 9 minutes ago. Isn't it a little bit too fast to apply? I just finished reading cover letter but didn't manage to start looking at the rest. :)
It's pretty standard boilerplate stuff, there's not much in there to review and Sylwester is one of the maintainers listed for this code so I wasn't particularly expecting extra review.
Okay then. Probably it was one of fastest applies. :)
Best regards, Krzysztof
On Fri, Apr 21, 2017 at 06:58:00PM +0100, Mark Brown wrote:
On Fri, Apr 21, 2017 at 07:31:42PM +0200, Krzysztof Kozlowski wrote:
Although Sylwester is known of writing good quality code and can be trusted but he posted it just 9 minutes ago. Isn't it a little bit too fast to apply? I just finished reading cover letter but didn't manage to start looking at the rest. :)
It's pretty standard boilerplate stuff, there's not much in there to review and Sylwester is one of the maintainers listed for this code so I wasn't particularly expecting extra review.
Off the list, off-topic,
Mutt is complaining that your key used to sign the mails has expired: gpg: Note: This key has expired! Primary key fingerprint: 3F25 68AA C269 98F9 E813 A1C5 C3F4 36CA 30F5 D8EB Subkey fingerprint: ADE6 68AA 6757 18B5 9FE2 9FEA 24D6 8B72 5D54 87D0
Best regards, Krzysztof
On Fri, Apr 21, 2017 at 08:07:10PM +0200, Krzysztof Kozlowski wrote:
Mutt is complaining that your key used to sign the mails has expired: gpg: Note: This key has expired! Primary key fingerprint: 3F25 68AA C269 98F9 E813 A1C5 C3F4 36CA 30F5 D8EB Subkey fingerprint: ADE6 68AA 6757 18B5 9FE2 9FEA 24D6 8B72 5D54 87D0
gpg --refresh-keys should fix that.
On Fri, Apr 21, 2017 at 07:19:49PM +0200, Sylwester Nawrocki wrote:
This patch adds DT binding documentation for Odroid XU3/4 sound subsystem.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
.../devicetree/bindings/sound/samsung,odroid.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/samsung,odroid.txt
diff --git a/Documentation/devicetree/bindings/sound/samsung,odroid.txt b/Documentation/devicetree/bindings/sound/samsung,odroid.txt new file mode 100644 index 0000000..c1ac70c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.txt @@ -0,0 +1,57 @@ +Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec
+Required properties:
- compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
"samsung,odroidxu4-audio" - for Odroid XU4 board
- model - the user-visible name of this sound complex
ASoC will support "label" soon (see graph support). Use that instead.
- 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
- controller
- 'codec' subnode with a 'sound-dai' property containing list of phandles
- to the CODEC nodes, first entry must be corresponding to the MAX98090
- CODEC and the second entry must be the phandle of the HDMI IP block node
These are not properties, so move them to a sub-node section.
- clocks - should contain entries matching clock names in the clock-names
- property
- clock-names - should contain following entries:
- "epll" - indicating the EPLL output clock
- "i2s_rclk" - indicating the RCLK (root) clock of the I2S0 controller
At least the 2nd one should be in the i2s node. This node isn't really a h/w block, so it shouldn't have clocks IMO.
- samsung,audio-widgets - this property specifies off-codec audio elements
- like headphones or speakers, for details see widgets.txt
- samsung,audio-routing - a list of the connections between audio
- components; each entry is a pair of strings, the first being the
- connection's sink, the second being the connection's source;
- valid names for sources and sinks are the MAX98090's pins (as
- documented in its binding), and the jacks on the board
- For Odroid X2:
"Headphone Jack", "Mic Jack", "DMIC"
- For Odroid U3, XU3:
"Headphone Jack", "Speakers"
- For Odroid XU4:
no entries
+Example:
+sound {
- compatible = "samsung,odroidxu3-audio";
- samsung,cpu-dai = <&i2s0>;
- samsung,codec-dai = <&max98090>;
Not documented. Nor needed?
- model = "Odroid-XU3";
- samsung,audio-routing =
"Headphone Jack", "HPL",
"Headphone Jack", "HPR",
"IN1", "Mic Jack",
"Mic Jack", "MICBIAS";
- clocks = <&clock CLK_FOUT_EPLL>, <&i2s0 CLK_I2S_RCLK_SRC>;
- clock-names = "epll", "sclk_i2s";
- cpu {
sound-dai = <&i2s0 0>;
- };
- codec {
sound-dai = <&hdmi>, <&max98090>;
- };
+};
1.9.1
On 04/28/2017 07:03 PM, Rob Herring wrote:
On Fri, Apr 21, 2017 at 07:19:49PM +0200, Sylwester Nawrocki wrote:
--- /dev/null +++ b/Documentation/devicetree/bindings/sound/samsung,odroid.txt @@ -0,0 +1,57 @@ +Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec
+Required properties:
- compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
"samsung,odroidxu4-audio" - for Odroid XU4 board
- model - the user-visible name of this sound complex
ASoC will support "label" soon (see graph support). Use that instead.
I could change that but it now might be too late since the patch has been merged in v4.12-rc1. Sorry, I couldn't get back to this earlier.
- clocks - should contain entries matching clock names in the clock-names
- property
- clock-names - should contain following entries:
- "epll" - indicating the EPLL output clock
- "i2s_rclk" - indicating the RCLK (root) clock of the I2S0 controller
At least the 2nd one should be in the i2s node. This node isn't really a h/w block, so it shouldn't have clocks IMO.
"i2s_rclk" is a clock exposed by the I2S controller.
The RCLK clock has already assigned clock parent in DT:
&i2s0 { assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>; assigned-clock-parents = <&clock_audss EXYNOS_SCLK_I2S>; };
In fact the sound card is not a consumer of this clock, the clock is used only internally in the I2S device. I could try to drop it and use ASoC internal API for CPU DAI clock setting.
But I have no idea what else could be done with the PLL, it belongs to the audio card and the card driver must somehow get hold of that clock to configure its frequency depending on audio sampling rate.
+Example:
+sound {
- compatible = "samsung,odroidxu3-audio";
- samsung,cpu-dai = <&i2s0>;
- samsung,codec-dai = <&max98090>;
Not documented. Nor needed?
Yes, I will remove these, that's a leftover from initial versions of the binding.
-- Thanks, Sylwester
This dedicated driver allows to support SoC specific clock settings and helps to ensure proper number of channels gets negotiated in multicodec system configurations.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- sound/soc/samsung/Kconfig | 8 ++ sound/soc/samsung/Makefile | 2 + sound/soc/samsung/odroid.c | 219 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 sound/soc/samsung/odroid.c
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index f1f1d79..0520f5a 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -185,6 +185,14 @@ config SND_SOC_SNOW Say Y if you want to add audio support for various Snow boards based on Exynos5 series of SoCs.
+config SND_SOC_ODROID + tristate "Audio support for Odroid XU3/XU4" + depends on SND_SOC_SAMSUNG && I2C + select SND_SOC_MAX98090 + select SND_SAMSUNG_I2S + help + Say Y here to enable audio support for the Odroid XU3/XU4. + config SND_SOC_ARNDALE_RT5631_ALC5631 tristate "Audio support for RT5631(ALC5631) on Arndale Board" depends on I2C diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index b5df5e2e..b6c2ee3 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -40,6 +40,7 @@ snd-soc-tobermory-objs := tobermory.o snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o +snd-soc-odroid-objs := odroid.o snd-soc-arndale-rt5631-objs := arndale_rt5631.o snd-soc-tm2-wm5110-objs := tm2_wm5110.o
@@ -62,5 +63,6 @@ obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o +obj-$(CONFIG_SND_SOC_ODROID) += snd-soc-odroid.o obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c new file mode 100644 index 0000000..0c0b00e --- /dev/null +++ b/sound/soc/samsung/odroid.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/pcm_params.h> +#include "i2s.h" +#include "i2s-regs.h" + +struct odroid_priv { + struct snd_soc_card card; + struct snd_soc_dai_link dai_link; + + struct clk *pll; + struct clk *rclk; +}; + +static int odroid_card_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); + return 0; +} + +static int odroid_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); + unsigned int pll_freq, rclk_freq; + int ret; + + switch (params_rate(params)) { + case 32000: + case 64000: + pll_freq = 131072000U; + break; + case 44100: + case 88200: + case 176400: + pll_freq = 180633600U; + break; + case 48000: + case 96000: + case 192000: + pll_freq = 196608000U; + break; + default: + return -EINVAL; + } + + ret = clk_set_rate(priv->pll, pll_freq + 1); + if (ret < 0) + return ret; + + rclk_freq = params_rate(params) * 256 * 4; + + ret = clk_set_rate(priv->rclk, rclk_freq); + if (ret < 0) + return ret; + + if (rtd->num_codecs > 1) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[1]; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct snd_soc_ops odroid_card_ops = { + .startup = odroid_card_startup, + .hw_params = odroid_card_hw_params, +}; + +static void odroid_put_codec_of_nodes(struct snd_soc_dai_link *link) +{ + struct snd_soc_dai_link_component *component = link->codecs; + int i; + + for (i = 0; i < link->num_codecs; i++, component++) { + if (!component->of_node) + break; + of_node_put(component->of_node); + } +} + +static int odroid_audio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *cpu, *codec; + struct odroid_priv *priv; + struct snd_soc_dai_link *link; + struct snd_soc_card *card; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + card = &priv->card; + card->dev = dev; + + card->owner = THIS_MODULE; + card->fully_routed = true; + + snd_soc_card_set_drvdata(card, priv); + + priv->pll = devm_clk_get(dev, "epll"); + if (IS_ERR(priv->pll)) + return PTR_ERR(priv->pll); + + priv->rclk = devm_clk_get(dev, "i2s_rclk"); + if (IS_ERR(priv->rclk)) + return PTR_ERR(priv->rclk); + + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret < 0) + return ret; + + if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { + ret = snd_soc_of_parse_audio_simple_widgets(card, + "samsung,audio-widgets"); + if (ret < 0) + return ret; + } + + if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { + ret = snd_soc_of_parse_audio_routing(card, + "samsung,audio-routing"); + if (ret < 0) + return ret; + } + + link = &priv->dai_link; + + link->ops = &odroid_card_ops; + link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + card->dai_link = &priv->dai_link; + card->num_links = 1; + + cpu = of_get_child_by_name(dev->of_node, "cpu"); + codec = of_get_child_by_name(dev->of_node, "codec"); + + link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); + if (!link->cpu_of_node) { + dev_err(dev, "Failed parsing cpu/sound-dai property\n"); + return -EINVAL; + } + + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + if (ret < 0) + goto err_put_codec_n; + + link->platform_of_node = link->cpu_of_node; + + link->name = "Primary"; + link->stream_name = link->name; + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) { + dev_err(dev, "snd_soc_register_card() failed: %d\n", ret); + goto err_put_i2s_n; + } + + return 0; + +err_put_i2s_n: + of_node_put(link->cpu_of_node); +err_put_codec_n: + odroid_put_codec_of_nodes(link); + return ret; +} + +static int odroid_audio_remove(struct platform_device *pdev) +{ + struct odroid_priv *priv = platform_get_drvdata(pdev); + + of_node_put(priv->dai_link.cpu_of_node); + odroid_put_codec_of_nodes(&priv->dai_link); + + return 0; +} + +static const struct of_device_id odroid_audio_of_match[] = { + { .compatible = "samsung,odroid-xu3-audio" }, + { .compatible = "samsung,odroid-xu4-audio"}, + { }, +}; +MODULE_DEVICE_TABLE(of, odroid_audio_of_match); + +static struct platform_driver odroid_audio_driver = { + .driver = { + .name = "odroid-audio", + .of_match_table = odroid_audio_of_match, + .pm = &snd_soc_pm_ops, + }, + .probe = odroid_audio_probe, + .remove = odroid_audio_remove, +}; +module_platform_driver(odroid_audio_driver); + +MODULE_AUTHOR("Sylwester Nawrocki s.nawrocki@samsung.com"); +MODULE_DESCRIPTION("Odroid XU3/XU4 audio support"); +MODULE_LICENSE("GPL v2");
The patch
ASoC: samsung: Add Odroid ASoC machine driver
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From aba611fc4c69896f1355ff0b8ff0ff21c9b5b6fb Mon Sep 17 00:00:00 2001
From: Sylwester Nawrocki s.nawrocki@samsung.com Date: Fri, 21 Apr 2017 19:19:50 +0200 Subject: [PATCH] ASoC: samsung: Add Odroid ASoC machine driver
This dedicated driver allows to support SoC specific clock settings and helps to ensure proper number of channels gets negotiated in multicodec system configurations.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/samsung/Kconfig | 8 ++ sound/soc/samsung/Makefile | 2 + sound/soc/samsung/odroid.c | 219 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 sound/soc/samsung/odroid.c
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index f1f1d7959a1b..0520f5afd7cc 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -185,6 +185,14 @@ config SND_SOC_SNOW Say Y if you want to add audio support for various Snow boards based on Exynos5 series of SoCs.
+config SND_SOC_ODROID + tristate "Audio support for Odroid XU3/XU4" + depends on SND_SOC_SAMSUNG && I2C + select SND_SOC_MAX98090 + select SND_SAMSUNG_I2S + help + Say Y here to enable audio support for the Odroid XU3/XU4. + config SND_SOC_ARNDALE_RT5631_ALC5631 tristate "Audio support for RT5631(ALC5631) on Arndale Board" depends on I2C diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index b5df5e2e3d94..b6c2ee358333 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -40,6 +40,7 @@ snd-soc-tobermory-objs := tobermory.o snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o +snd-soc-odroid-objs := odroid.o snd-soc-arndale-rt5631-objs := arndale_rt5631.o snd-soc-tm2-wm5110-objs := tm2_wm5110.o
@@ -62,5 +63,6 @@ obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o +obj-$(CONFIG_SND_SOC_ODROID) += snd-soc-odroid.o obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c new file mode 100644 index 000000000000..0c0b00e40646 --- /dev/null +++ b/sound/soc/samsung/odroid.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <sound/soc.h> +#include <sound/pcm_params.h> +#include "i2s.h" +#include "i2s-regs.h" + +struct odroid_priv { + struct snd_soc_card card; + struct snd_soc_dai_link dai_link; + + struct clk *pll; + struct clk *rclk; +}; + +static int odroid_card_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); + return 0; +} + +static int odroid_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); + unsigned int pll_freq, rclk_freq; + int ret; + + switch (params_rate(params)) { + case 32000: + case 64000: + pll_freq = 131072000U; + break; + case 44100: + case 88200: + case 176400: + pll_freq = 180633600U; + break; + case 48000: + case 96000: + case 192000: + pll_freq = 196608000U; + break; + default: + return -EINVAL; + } + + ret = clk_set_rate(priv->pll, pll_freq + 1); + if (ret < 0) + return ret; + + rclk_freq = params_rate(params) * 256 * 4; + + ret = clk_set_rate(priv->rclk, rclk_freq); + if (ret < 0) + return ret; + + if (rtd->num_codecs > 1) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[1]; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + } + + return 0; +} + +static const struct snd_soc_ops odroid_card_ops = { + .startup = odroid_card_startup, + .hw_params = odroid_card_hw_params, +}; + +static void odroid_put_codec_of_nodes(struct snd_soc_dai_link *link) +{ + struct snd_soc_dai_link_component *component = link->codecs; + int i; + + for (i = 0; i < link->num_codecs; i++, component++) { + if (!component->of_node) + break; + of_node_put(component->of_node); + } +} + +static int odroid_audio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *cpu, *codec; + struct odroid_priv *priv; + struct snd_soc_dai_link *link; + struct snd_soc_card *card; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + card = &priv->card; + card->dev = dev; + + card->owner = THIS_MODULE; + card->fully_routed = true; + + snd_soc_card_set_drvdata(card, priv); + + priv->pll = devm_clk_get(dev, "epll"); + if (IS_ERR(priv->pll)) + return PTR_ERR(priv->pll); + + priv->rclk = devm_clk_get(dev, "i2s_rclk"); + if (IS_ERR(priv->rclk)) + return PTR_ERR(priv->rclk); + + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret < 0) + return ret; + + if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) { + ret = snd_soc_of_parse_audio_simple_widgets(card, + "samsung,audio-widgets"); + if (ret < 0) + return ret; + } + + if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) { + ret = snd_soc_of_parse_audio_routing(card, + "samsung,audio-routing"); + if (ret < 0) + return ret; + } + + link = &priv->dai_link; + + link->ops = &odroid_card_ops; + link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + card->dai_link = &priv->dai_link; + card->num_links = 1; + + cpu = of_get_child_by_name(dev->of_node, "cpu"); + codec = of_get_child_by_name(dev->of_node, "codec"); + + link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); + if (!link->cpu_of_node) { + dev_err(dev, "Failed parsing cpu/sound-dai property\n"); + return -EINVAL; + } + + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + if (ret < 0) + goto err_put_codec_n; + + link->platform_of_node = link->cpu_of_node; + + link->name = "Primary"; + link->stream_name = link->name; + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) { + dev_err(dev, "snd_soc_register_card() failed: %d\n", ret); + goto err_put_i2s_n; + } + + return 0; + +err_put_i2s_n: + of_node_put(link->cpu_of_node); +err_put_codec_n: + odroid_put_codec_of_nodes(link); + return ret; +} + +static int odroid_audio_remove(struct platform_device *pdev) +{ + struct odroid_priv *priv = platform_get_drvdata(pdev); + + of_node_put(priv->dai_link.cpu_of_node); + odroid_put_codec_of_nodes(&priv->dai_link); + + return 0; +} + +static const struct of_device_id odroid_audio_of_match[] = { + { .compatible = "samsung,odroid-xu3-audio" }, + { .compatible = "samsung,odroid-xu4-audio"}, + { }, +}; +MODULE_DEVICE_TABLE(of, odroid_audio_of_match); + +static struct platform_driver odroid_audio_driver = { + .driver = { + .name = "odroid-audio", + .of_match_table = odroid_audio_of_match, + .pm = &snd_soc_pm_ops, + }, + .probe = odroid_audio_probe, + .remove = odroid_audio_remove, +}; +module_platform_driver(odroid_audio_driver); + +MODULE_AUTHOR("Sylwester Nawrocki s.nawrocki@samsung.com"); +MODULE_DESCRIPTION("Odroid XU3/XU4 audio support"); +MODULE_LICENSE("GPL v2");
The new sound card DT binding is used for Odroid XU3 in order to properly support the HDMI audio path. Clocks configuration is changed so the I2S controller is now the bit and the frame clock master with EPLL as the root clock source.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com --- arch/arm/boot/dts/exynos4.dtsi | 1 + arch/arm/boot/dts/exynos5420.dtsi | 1 + arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi | 59 ++++++++++++++++++----- 3 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 18def1c..f3dcb7f 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -761,6 +761,7 @@ phy = <&hdmi_i2c_phy>; power-domains = <&pd_tv>; samsung,syscon-phandle = <&pmu_system_controller>; + #sound-dai-cells = <0>; status = "disabled"; };
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 7dc9dc8..c7d29b6 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -618,6 +618,7 @@ samsung,syscon-phandle = <&pmu_system_controller>; status = "disabled"; power-domains = <&disp_pd>; + #sound-dai-cells = <0>; };
hdmiphy: hdmiphy@145D0000 { diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi index 9493923..84703f7 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi @@ -11,15 +11,17 @@ * published by the Free Software Foundation. */
+#include <dt-bindings/sound/samsung-i2s.h> + / { sound: sound { - compatible = "simple-audio-card"; + compatible = "samsung,odroid-xu3-audio"; + model = "Odroid-XU3";
- simple-audio-card,name = "Odroid-XU3"; - simple-audio-card,widgets = + samsung,audio-widgets = "Headphone", "Headphone Jack", "Speakers", "Speakers"; - simple-audio-card,routing = + samsung,audio-routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "Headphone Jack", "MICBIAS", @@ -27,22 +29,51 @@ "Speakers", "SPKL", "Speakers", "SPKR";
- simple-audio-card,format = "i2s"; - simple-audio-card,bitclock-master = <&link0_codec>; - simple-audio-card,frame-master = <&link0_codec>; + clocks = <&clock CLK_FOUT_EPLL>, <&i2s0 CLK_I2S_RCLK_SRC>; + clock-names = "epll", "i2s_rclk";
- simple-audio-card,cpu { + cpu { sound-dai = <&i2s0 0>; - system-clock-frequency = <19200000>; }; - - link0_codec: simple-audio-card,codec { - sound-dai = <&max98090>; - clocks = <&i2s0 CLK_I2S_CDCLK>; + codec { + sound-dai = <&hdmi>, <&max98090>; }; }; };
+&clock_audss { + assigned-clocks = <&clock_audss EXYNOS_DOUT_SRP>, + <&clock CLK_FOUT_EPLL>; + assigned-clock-rates = <(196608000 / 256)>, + <196608000>; +}; + +&sound { + assigned-clocks = <&clock CLK_MOUT_EPLL>, + <&clock CLK_MOUT_MAU_EPLL>, + <&clock CLK_MOUT_USER_MAU_EPLL>, + <&clock_audss EXYNOS_MOUT_AUDSS>, + <&clock_audss EXYNOS_MOUT_I2S>, + <&clock_audss EXYNOS_DOUT_SRP>, + <&clock_audss EXYNOS_DOUT_AUD_BUS>, + <&clock_audss EXYNOS_DOUT_I2S>; + + assigned-clock-parents = <&clock CLK_FOUT_EPLL>, + <&clock CLK_MOUT_EPLL>, + <&clock CLK_MOUT_MAU_EPLL>, + <&clock CLK_MAU_EPLL>, + <&clock_audss EXYNOS_MOUT_AUDSS>; + + assigned-clock-rates = <0>, + <0>, + <0>, + <0>, + <0>, + <196608000>, + <(196608000 / 2)>, + <196608000>; +}; + &hsi2c_5 { status = "okay"; max98090: max98090@10 { @@ -58,4 +89,6 @@
&i2s0 { status = "okay"; + assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>; + assigned-clock-parents = <&clock_audss EXYNOS_SCLK_I2S>; };
On Fri, Apr 21, 2017 at 07:19:51PM +0200, Sylwester Nawrocki wrote:
The new sound card DT binding is used for Odroid XU3 in order to properly support the HDMI audio path. Clocks configuration is changed so the I2S controller is now the bit and the frame clock master with EPLL as the root clock source.
Signed-off-by: Sylwester Nawrocki s.nawrocki@samsung.com
arch/arm/boot/dts/exynos4.dtsi | 1 + arch/arm/boot/dts/exynos5420.dtsi | 1 + arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi | 59 ++++++++++++++++++----- 3 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 18def1c..f3dcb7f 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -761,6 +761,7 @@ phy = <&hdmi_i2c_phy>; power-domains = <&pd_tv>; samsung,syscon-phandle = <&pmu_system_controller>;
status = "disabled"; };#sound-dai-cells = <0>;
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 7dc9dc8..c7d29b6 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -618,6 +618,7 @@ samsung,syscon-phandle = <&pmu_system_controller>; status = "disabled"; power-domains = <&disp_pd>;
#sound-dai-cells = <0>;
};
hdmiphy: hdmiphy@145D0000 {
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi index 9493923..84703f7 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi @@ -11,15 +11,17 @@
- published by the Free Software Foundation.
*/
+#include <dt-bindings/sound/samsung-i2s.h>
/ { sound: sound {
compatible = "simple-audio-card";
compatible = "samsung,odroid-xu3-audio";
model = "Odroid-XU3";
simple-audio-card,name = "Odroid-XU3";
simple-audio-card,widgets =
samsung,audio-widgets = "Headphone", "Headphone Jack", "Speakers", "Speakers";
simple-audio-card,routing =
samsung,audio-routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "Headphone Jack", "MICBIAS",
@@ -27,22 +29,51 @@ "Speakers", "SPKL", "Speakers", "SPKR";
simple-audio-card,format = "i2s";
simple-audio-card,bitclock-master = <&link0_codec>;
simple-audio-card,frame-master = <&link0_codec>;
clocks = <&clock CLK_FOUT_EPLL>, <&i2s0 CLK_I2S_RCLK_SRC>;
clock-names = "epll", "i2s_rclk";
simple-audio-card,cpu {
cpu { sound-dai = <&i2s0 0>;
};system-clock-frequency = <19200000>;
link0_codec: simple-audio-card,codec {
sound-dai = <&max98090>;
clocks = <&i2s0 CLK_I2S_CDCLK>;
codec {
}; };sound-dai = <&hdmi>, <&max98090>;
};
+&clock_audss {
- assigned-clocks = <&clock_audss EXYNOS_DOUT_SRP>,
<&clock CLK_FOUT_EPLL>;
- assigned-clock-rates = <(196608000 / 256)>,
<196608000>;
+};
+&sound {
- assigned-clocks = <&clock CLK_MOUT_EPLL>,
<&clock CLK_MOUT_MAU_EPLL>,
<&clock CLK_MOUT_USER_MAU_EPLL>,
<&clock_audss EXYNOS_MOUT_AUDSS>,
<&clock_audss EXYNOS_MOUT_I2S>,
<&clock_audss EXYNOS_DOUT_SRP>,
<&clock_audss EXYNOS_DOUT_AUD_BUS>,
<&clock_audss EXYNOS_DOUT_I2S>;
- assigned-clock-parents = <&clock CLK_FOUT_EPLL>,
<&clock CLK_MOUT_EPLL>,
<&clock CLK_MOUT_MAU_EPLL>,
<&clock CLK_MAU_EPLL>,
<&clock_audss EXYNOS_MOUT_AUDSS>;
- assigned-clock-rates = <0>,
<0>,
<0>,
<0>,
<0>,
<196608000>,
<(196608000 / 2)>,
<196608000>;
+};
Unless there is clear reson not to, I would prefer to put nodes sorted alphabetically. It helps avoiding conflicts and bring some logic.
Beside that, looks good for me.
You mentioned that DTS will be going in with next iteration. Sounds fine with me.
Best regards, Krzysztof
participants (5)
-
Krzysztof Kozlowski
-
Mark Brown
-
Rob Herring
-
Stephen Boyd
-
Sylwester Nawrocki