mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
Merge branch 'odroidxu3-4.9.y'
This commit is contained in:
@@ -185,9 +185,10 @@
|
||||
compatible = "samsung,exynos5420-audss-clock";
|
||||
reg = <0x03810000 0x0C>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MAU_EPLL>,
|
||||
<&clock CLK_SCLK_MAUDIO0>, <&clock CLK_SCLK_MAUPCM0>;
|
||||
clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in";
|
||||
clocks = <&clock CLK_FOUT_EPLL>, <&clock CLK_FIN_PLL>,
|
||||
<&clock CLK_MOUT_MAU_EPLL_USER>, <&clock CLK_SCLK_MAUDIO0>,
|
||||
<&clock CLK_SCLK_MAUPCM0>;
|
||||
clock-names = "fout_epll", "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in";
|
||||
};
|
||||
|
||||
mfc: codec@11000000 {
|
||||
|
||||
@@ -13,33 +13,25 @@
|
||||
|
||||
/ {
|
||||
sound: sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,name = "Odroid-XU3";
|
||||
simple-audio-card,widgets =
|
||||
"Headphone", "Headphone Jack",
|
||||
"Speakers", "Speakers";
|
||||
simple-audio-card,routing =
|
||||
"Headphone Jack", "HPL",
|
||||
"Headphone Jack", "HPR",
|
||||
"Headphone Jack", "MICBIAS",
|
||||
"IN1", "Headphone Jack",
|
||||
"Speakers", "SPKL",
|
||||
"Speakers", "SPKR";
|
||||
|
||||
simple-audio-card,format = "i2s";
|
||||
simple-audio-card,bitclock-master = <&link0_codec>;
|
||||
simple-audio-card,frame-master = <&link0_codec>;
|
||||
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
system-clock-frequency = <19200000>;
|
||||
};
|
||||
|
||||
link0_codec: simple-audio-card,codec {
|
||||
sound-dai = <&max98090>;
|
||||
clocks = <&i2s0 CLK_I2S_CDCLK>;
|
||||
};
|
||||
compatible = "hardkernel,odroid-max98090";
|
||||
card-name = "odroid-snd";
|
||||
clocks = <&clock CLK_FOUT_EPLL>,
|
||||
<&clock CLK_MOUT_EPLL>,
|
||||
<&clock CLK_MOUT_MAU_EPLL>,
|
||||
<&clock CLK_MOUT_MAU_EPLL_USER>,
|
||||
<&clock_audss EXYNOS_MOUT_AUDSS>,
|
||||
<&clock_audss EXYNOS_MOUT_I2S>,
|
||||
<&clock_audss EXYNOS_DOUT_SRP>,
|
||||
<&clock_audss EXYNOS_DOUT_AUD_BUS>,
|
||||
<&clock CLK_MAU_EPLL>;
|
||||
clock-names = "fout_epll", "mout_sclk_epll",
|
||||
"mout_mau_epll","mout_mau_epll_user",
|
||||
"mout_audss", "mout_i2s",
|
||||
"dout_srp","dout_aud_bus",
|
||||
"mau_epll_clk";
|
||||
samsung,i2s-controller = <&i2s0 0>;
|
||||
samsung,audio-codec = <&max98090>;
|
||||
codec-dai-name = "HiFi";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -50,8 +42,6 @@
|
||||
reg = <0x10>;
|
||||
interrupt-parent = <&gpx3>;
|
||||
interrupts = <2 0>;
|
||||
clocks = <&i2s0 CLK_I2S_CDCLK>;
|
||||
clock-names = "mclk";
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -254,17 +254,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&clock_audss {
|
||||
assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
|
||||
<&clock_audss EXYNOS_MOUT_I2S>,
|
||||
<&clock_audss EXYNOS_DOUT_AUD_BUS>;
|
||||
assigned-clock-parents = <&clock CLK_FIN_PLL>,
|
||||
<&clock_audss EXYNOS_MOUT_AUDSS>;
|
||||
assigned-clock-rates = <0>,
|
||||
<0>,
|
||||
<19200000>;
|
||||
};
|
||||
|
||||
&cpu0 {
|
||||
cpu-supply = <&buck6_reg>;
|
||||
};
|
||||
|
||||
44
arch/arm/boot/dts/exynos5422-odroidxu4-audio.dtsi
Normal file
44
arch/arm/boot/dts/exynos5422-odroidxu4-audio.dtsi
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Hardkernel Odroid XU3 Audio Codec device tree source
|
||||
*
|
||||
* Copyright (c) 2015 Krzysztof Kozlowski
|
||||
* Copyright (c) 2014 Collabora Ltd.
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/ {
|
||||
dummy_codec: spdif-transmitter {
|
||||
compatible = "linux,spdif-dit";
|
||||
status = "okay";
|
||||
};
|
||||
sound: sound {
|
||||
compatible = "hardkernel,odroid-max98090";
|
||||
card-name = "odroid-snd";
|
||||
clocks = <&clock CLK_FOUT_EPLL>,
|
||||
<&clock CLK_MOUT_EPLL>,
|
||||
<&clock CLK_MOUT_MAU_EPLL>,
|
||||
<&clock CLK_MOUT_MAU_EPLL_USER>,
|
||||
<&clock_audss EXYNOS_MOUT_AUDSS>,
|
||||
<&clock_audss EXYNOS_MOUT_I2S>,
|
||||
<&clock_audss EXYNOS_DOUT_SRP>,
|
||||
<&clock_audss EXYNOS_DOUT_AUD_BUS>,
|
||||
<&clock CLK_MAU_EPLL>;
|
||||
clock-names = "fout_epll", "mout_sclk_epll",
|
||||
"mout_mau_epll","mout_mau_epll_user",
|
||||
"mout_audss", "mout_i2s",
|
||||
"dout_srp","dout_aud_bus",
|
||||
"mau_epll_clk";
|
||||
samsung,i2s-controller = <&i2s0 0>;
|
||||
samsung,audio-codec = <&dummy_codec>;
|
||||
codec-dai-name = "dit-hifi";
|
||||
};
|
||||
};
|
||||
|
||||
&i2s0 {
|
||||
status = "okay";
|
||||
};
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
/dts-v1/;
|
||||
#include "exynos5422-odroidxu3-common.dtsi"
|
||||
#include "exynos5422-odroidxu4-audio.dtsi"
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
/ {
|
||||
|
||||
@@ -917,7 +917,7 @@ CONFIG_STANDALONE=y
|
||||
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
|
||||
CONFIG_FW_LOADER=y
|
||||
CONFIG_FIRMWARE_IN_KERNEL=y
|
||||
CONFIG_EXTRA_FIRMWARE="edid/1024x768.bin edid/1280x800.bin edid/1920x1080.bin edid/720x480.bin edid/800x600.bin edid/800x480.bin edid/1280x1024.bin edid/1280x720.bin edid/1440x900.bin edid/1680x1050.bin edid/1920x1080_50hz.bin edid/640x480.bin edid/720x576.bin edid/1024x600.bin"
|
||||
CONFIG_EXTRA_FIRMWARE="edid/1024x768.bin edid/1280x800.bin edid/1920x1080.bin edid/720x480.bin edid/800x600.bin edid/800x480.bin edid/1280x1024.bin edid/1280x720.bin edid/1440x900.bin edid/1680x1050.bin edid/1360x768.bin edid/1366x768.bin edid/1600x1200.bin edid/1600x900.bin edid/1920x1200_30hz.bin edid/1920x1080_50hz.bin edid/640x480.bin edid/720x576.bin edid/1024x600.bin"
|
||||
CONFIG_EXTRA_FIRMWARE_DIR="firmware"
|
||||
# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
|
||||
CONFIG_WANT_DEV_COREDUMP=y
|
||||
@@ -1470,6 +1470,7 @@ CONFIG_TOUCHSCREEN_MMS114=y
|
||||
# CONFIG_TOUCHSCREEN_ZFORCE is not set
|
||||
# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
|
||||
CONFIG_TOUCHSCREEN_SX865X=m
|
||||
# CONFIG_TOUCHSCREEN_DWAV_USB_MT is not set
|
||||
CONFIG_INPUT_MISC=y
|
||||
# CONFIG_INPUT_AD714X is not set
|
||||
# CONFIG_INPUT_ATMEL_CAPTOUCH is not set
|
||||
@@ -1598,6 +1599,7 @@ CONFIG_TCG_TIS_I2C_INFINEON=y
|
||||
# CONFIG_TCG_TIS_ST33ZP24_I2C is not set
|
||||
# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
|
||||
# CONFIG_XILLYBUS is not set
|
||||
CONFIG_EXYNOS_GPIOMEM=m
|
||||
|
||||
#
|
||||
# I2C support
|
||||
@@ -2611,18 +2613,18 @@ CONFIG_SND_SOC_SAMSUNG=y
|
||||
CONFIG_SND_SAMSUNG_PCM=y
|
||||
# CONFIG_SND_SAMSUNG_SPDIF is not set
|
||||
CONFIG_SND_SAMSUNG_I2S=y
|
||||
CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=y
|
||||
# CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994 is not set
|
||||
# CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF is not set
|
||||
CONFIG_SND_SOC_SMDK_WM8994_PCM=y
|
||||
CONFIG_SND_SOC_SNOW=y
|
||||
# CONFIG_SND_SOC_SMDK_WM8994_PCM is not set
|
||||
# CONFIG_SND_SOC_SNOW is not set
|
||||
# CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631 is not set
|
||||
CONFIG_SND_SOC_ODROID_MAX98090=y
|
||||
# CONFIG_SND_SOC_XTFPGA_I2S is not set
|
||||
CONFIG_SND_SOC_I2C_AND_SPI=y
|
||||
|
||||
#
|
||||
# CODEC drivers
|
||||
#
|
||||
CONFIG_SND_SOC_WM_HUBS=y
|
||||
# CONFIG_SND_SOC_AC97_CODEC is not set
|
||||
# CONFIG_SND_SOC_ADAU1701 is not set
|
||||
# CONFIG_SND_SOC_ADAU7002 is not set
|
||||
@@ -2650,7 +2652,6 @@ CONFIG_SND_SOC_WM_HUBS=y
|
||||
# CONFIG_SND_SOC_GTM601 is not set
|
||||
# CONFIG_SND_SOC_INNO_RK3036 is not set
|
||||
CONFIG_SND_SOC_MAX98090=y
|
||||
CONFIG_SND_SOC_MAX98095=y
|
||||
# CONFIG_SND_SOC_MAX98504 is not set
|
||||
# CONFIG_SND_SOC_MAX9860 is not set
|
||||
# CONFIG_SND_SOC_PCM1681 is not set
|
||||
@@ -2665,7 +2666,7 @@ CONFIG_SND_SOC_MAX98095=y
|
||||
# CONFIG_SND_SOC_RT5677_SPI is not set
|
||||
# CONFIG_SND_SOC_SGTL5000 is not set
|
||||
# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
|
||||
# CONFIG_SND_SOC_SPDIF is not set
|
||||
CONFIG_SND_SOC_SPDIF=y
|
||||
# CONFIG_SND_SOC_SSM2602_SPI is not set
|
||||
# CONFIG_SND_SOC_SSM2602_I2C is not set
|
||||
# CONFIG_SND_SOC_SSM4567 is not set
|
||||
@@ -2702,7 +2703,6 @@ CONFIG_SND_SOC_MAX98095=y
|
||||
# CONFIG_SND_SOC_WM8974 is not set
|
||||
# CONFIG_SND_SOC_WM8978 is not set
|
||||
# CONFIG_SND_SOC_WM8985 is not set
|
||||
CONFIG_SND_SOC_WM8994=y
|
||||
# CONFIG_SND_SOC_NAU8810 is not set
|
||||
# CONFIG_SND_SOC_TPA6130A2 is not set
|
||||
CONFIG_SND_SIMPLE_CARD_UTILS=y
|
||||
|
||||
@@ -131,33 +131,41 @@ static void exynos_audss_clk_teardown(void)
|
||||
/* register exynos_audss clocks */
|
||||
static int exynos_audss_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
const char *mout_audss_p[] = {"fin_pll", "fout_epll"};
|
||||
const char *mout_audss_p[] = {"fin_pll", "mout_mau_epll_user"};
|
||||
const char *mout_i2s_p[] = {"mout_audss", "cdclk0", "sclk_audio0"};
|
||||
const char *sclk_pcm_p = "sclk_pcm0";
|
||||
struct clk *pll_ref, *pll_in, *cdclk, *sclk_audio, *sclk_pcm_in;
|
||||
const struct exynos_audss_clk_drvdata *variant;
|
||||
struct resource *res;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int i, ret = 0;
|
||||
|
||||
variant = of_device_get_match_data(&pdev->dev);
|
||||
if (!variant)
|
||||
return -EINVAL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
reg_base = of_iomap(np, 0);
|
||||
if (IS_ERR(reg_base)) {
|
||||
dev_err(&pdev->dev, "failed to map audss registers\n");
|
||||
return PTR_ERR(reg_base);
|
||||
}
|
||||
|
||||
epll = ERR_PTR(-ENODEV);
|
||||
|
||||
clk_table = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS,
|
||||
GFP_KERNEL);
|
||||
if (!clk_table)
|
||||
return -ENOMEM;
|
||||
|
||||
epll = devm_clk_get(&pdev->dev, "fout_epll");
|
||||
ret = clk_prepare_enable(epll);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to prepare the epll clock\n");
|
||||
return ret;
|
||||
}
|
||||
clk_set_rate(epll, 180633600);
|
||||
dev_info(&pdev->dev, "epll %ld\n", clk_get_rate(epll));
|
||||
clk_put(epll);
|
||||
|
||||
clk_data.clks = clk_table;
|
||||
clk_data.clk_num = variant->num_clks;
|
||||
|
||||
@@ -167,17 +175,6 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
||||
mout_audss_p[0] = __clk_get_name(pll_ref);
|
||||
if (!IS_ERR(pll_in)) {
|
||||
mout_audss_p[1] = __clk_get_name(pll_in);
|
||||
|
||||
if (variant->enable_epll) {
|
||||
epll = pll_in;
|
||||
|
||||
ret = clk_prepare_enable(epll);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to prepare the epll clock\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss",
|
||||
mout_audss_p, ARRAY_SIZE(mout_audss_p),
|
||||
@@ -290,7 +287,17 @@ static struct platform_driver exynos_audss_clk_driver = {
|
||||
.remove = exynos_audss_clk_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(exynos_audss_clk_driver);
|
||||
static int __init exynos_audss_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&exynos_audss_clk_driver);
|
||||
}
|
||||
core_initcall(exynos_audss_clk_init);
|
||||
|
||||
static void __exit exynos_audss_clk_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&exynos_audss_clk_driver);
|
||||
}
|
||||
module_exit(exynos_audss_clk_exit);
|
||||
|
||||
MODULE_AUTHOR("Padmavathi Venna <padma.v@samsung.com>");
|
||||
MODULE_DESCRIPTION("Exynos Audio Subsystem Clock Controller");
|
||||
|
||||
@@ -454,6 +454,7 @@ PNAME(mout_maudio0_p) = {"fin_pll", "maudio_clk", "mout_sclk_dpll",
|
||||
"mout_sclk_epll", "mout_sclk_rpll"};
|
||||
PNAME(mout_mau_epll_clk_p) = {"mout_sclk_epll", "mout_sclk_dpll",
|
||||
"mout_sclk_mpll", "mout_sclk_spll"};
|
||||
PNAME(mout_mau_epll_clk_user_p) = {"dout_osc_div", "mout_mau_epll_clk"};
|
||||
PNAME(mout_mclk_cdrex_p) = {"mout_bpll", "mout_mx_mspll_ccore"};
|
||||
|
||||
/* List of parents specific to exynos5800 */
|
||||
@@ -536,8 +537,9 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
|
||||
|
||||
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(0, "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),
|
||||
|
||||
@@ -616,7 +618,6 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
|
||||
|
||||
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
|
||||
mout_group5_5800_p, SRC_TOP7, 16, 2),
|
||||
MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2),
|
||||
|
||||
MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1),
|
||||
};
|
||||
@@ -703,7 +704,7 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
|
||||
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(CLK_MOUT_DPLL, "mout_sclk_dpll", mout_dpll_p, SRC_TOP6, 24, 1),
|
||||
MUX(0, "mout_sclk_cpll", mout_cpll_p, SRC_TOP6, 28, 1),
|
||||
|
||||
@@ -797,6 +798,11 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
|
||||
MUX(0, "mout_spi0_isp", mout_group2_p, SRC_ISP, 12, 3),
|
||||
MUX(0, "mout_spi1_isp", mout_group2_p, SRC_ISP, 16, 3),
|
||||
MUX(0, "mout_isp_sensor", mout_group2_p, SRC_ISP, 28, 3),
|
||||
|
||||
MUX(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7,
|
||||
20, 2),
|
||||
MUX(CLK_MOUT_MAU_EPLL_USER, "mout_mau_epll_clk_user", mout_mau_epll_clk_user_p,
|
||||
SRC_TOP9, 8, 1),
|
||||
};
|
||||
|
||||
static const struct samsung_div_clock exynos5x_div_clks[] __initconst = {
|
||||
@@ -998,8 +1004,8 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
|
||||
GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1",
|
||||
SRC_MASK_TOP2, 24, 0, 0),
|
||||
|
||||
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
|
||||
SRC_MASK_TOP7, 20, 0, 0),
|
||||
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk_user",
|
||||
GATE_BUS_TOP, 23, 0, 0),
|
||||
|
||||
/* sclk */
|
||||
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_uart0",
|
||||
@@ -1287,7 +1293,30 @@ static const struct samsung_pll_rate_table exynos5420_vpll_rates[] __initconst =
|
||||
PLL_35XX_RATE(177000000, 118, 2, 3),
|
||||
PLL_35XX_RATE(100000000, 200, 3, 4),
|
||||
};
|
||||
|
||||
|
||||
static struct samsung_pll_rate_table epll_24mhz_tbl[] __initdata = {
|
||||
/* sorted in descending order */
|
||||
/* PLL_36XX_RATE(rate, m, p, s, k) */
|
||||
PLL_36XX_RATE(600000000, 100, 2, 1, 0),
|
||||
PLL_36XX_RATE(400000000, 200, 3, 2, 0),
|
||||
PLL_36XX_RATE(393216000, 197, 3, 2, 39846),
|
||||
PLL_36XX_RATE(361267200, 301, 5, 2, 3671),
|
||||
PLL_36XX_RATE(262144000, 131, 3, 2, 4719),
|
||||
PLL_36XX_RATE(200000000, 200, 3, 3, 0),
|
||||
PLL_36XX_RATE(196608000, 197, 3, 3, 39846),
|
||||
PLL_36XX_RATE(180633600, 301, 5, 3, 3671),
|
||||
PLL_36XX_RATE(131072000, 131, 3, 3, 4719),
|
||||
PLL_36XX_RATE(100000000, 200, 3, 4, 0),
|
||||
PLL_36XX_RATE( 98304000, 197, 3, 4, 39846),
|
||||
PLL_36XX_RATE( 90316800, 301, 5, 4, 3671),
|
||||
PLL_36XX_RATE( 73728000, 393, 4, 5, 14156),
|
||||
PLL_36XX_RATE( 67737600, 452, 5, 5, 27263),
|
||||
PLL_36XX_RATE( 65536000, 131, 3, 4, 4719),
|
||||
PLL_36XX_RATE( 49152000, 197, 3, 5, 39846),
|
||||
PLL_36XX_RATE( 45158400, 301, 5, 5, 3671),
|
||||
PLL_36XX_RATE( 32768000, 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,
|
||||
@@ -1414,6 +1443,7 @@ static void __init exynos5x_clk_init(struct device_node *np,
|
||||
exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
|
||||
exynos5x_plls[bpll].rate_table = exynos5420_pll2550x_24mhz_tbl;
|
||||
exynos5x_plls[vpll].rate_table = exynos5420_vpll_rates;
|
||||
exynos5x_plls[epll].rate_table = epll_24mhz_tbl;
|
||||
}
|
||||
|
||||
samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls),
|
||||
|
||||
@@ -244,6 +244,7 @@ static const struct clk_ops samsung_pll35xx_clk_min_ops = {
|
||||
#define PLL36XX_SDIV_SHIFT (0)
|
||||
#define PLL36XX_KDIV_SHIFT (0)
|
||||
#define PLL36XX_LOCK_STAT_SHIFT (29)
|
||||
#define PLL36XX_PLL_ENABLE_SHIFT (31)
|
||||
|
||||
static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
@@ -284,7 +285,7 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct samsung_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 tmp, pll_con0, pll_con1;
|
||||
u32 tmp, pll_con0, pll_con1, locktime;
|
||||
const struct samsung_pll_rate_table *rate;
|
||||
|
||||
rate = samsung_get_pll_settings(pll, drate);
|
||||
@@ -296,30 +297,24 @@ static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
|
||||
pll_con0 = readl_relaxed(pll->con_reg);
|
||||
pll_con1 = readl_relaxed(pll->con_reg + 4);
|
||||
|
||||
if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
|
||||
/* If only s change, change just s value only*/
|
||||
pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
|
||||
pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
|
||||
writel_relaxed(pll_con0, pll->con_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set PLL lock time. */
|
||||
writel_relaxed(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
|
||||
|
||||
/* Change PLL PMS values */
|
||||
pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
|
||||
(PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
|
||||
(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
|
||||
pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
|
||||
(rate->pdiv << PLL36XX_PDIV_SHIFT) |
|
||||
(rate->sdiv << PLL36XX_SDIV_SHIFT);
|
||||
writel_relaxed(pll_con0, pll->con_reg);
|
||||
|
||||
/* Change PLL PMS values */
|
||||
pll_con0 |= rate->mdiv << PLL36XX_MDIV_SHIFT;
|
||||
pll_con0 |= rate->pdiv << PLL36XX_PDIV_SHIFT;
|
||||
pll_con0 |= rate->sdiv << PLL36XX_SDIV_SHIFT;
|
||||
pll_con0 |= 1 << PLL36XX_PLL_ENABLE_SHIFT;
|
||||
|
||||
pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
|
||||
pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
|
||||
|
||||
/* Set PLL lock time. */
|
||||
locktime = PLL36XX_LOCK_FACTOR * rate->pdiv;
|
||||
writel_relaxed(locktime, pll->lock_reg);
|
||||
writel_relaxed(pll_con0, pll->con_reg);
|
||||
writel_relaxed(pll_con1, pll->con_reg + 4);
|
||||
|
||||
/* wait_lock_time */
|
||||
|
||||
@@ -497,6 +497,24 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
|
||||
0x54, 0x4A, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 84750000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x23, 0x11, 0x40, 0x30, 0x1E, 0xC7,
|
||||
0x84, 0xE8, 0xD4, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x48, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 85860000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x24, 0x11, 0x40, 0x30, 0xD2, 0xC8,
|
||||
0x84, 0xE8, 0xD5, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x48, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 88750000,
|
||||
.conf = {
|
||||
@@ -506,6 +524,15 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
|
||||
0x54, 0x45, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 89750000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x25, 0x11, 0x40, 0x30, 0x26, 0xC9,
|
||||
0x83, 0xE8, 0xE0, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x89, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 106500000,
|
||||
.conf = {
|
||||
@@ -515,6 +542,24 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
|
||||
0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 106560000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x2C, 0x12, 0x40, 0x78, 0x73, 0xCA,
|
||||
0x85, 0xE8, 0x0B, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 107800000,
|
||||
.conf = {
|
||||
0x01, 0x51, 0x2D, 0x15, 0x40, 0x01, 0x00, 0xC8,
|
||||
0x82, 0xC8, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x66,
|
||||
0x54, 0xC7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 108000000,
|
||||
.conf = {
|
||||
@@ -533,6 +578,15 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
|
||||
0x54, 0x6A, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 119000000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x31, 0x14, 0x40, 0x78, 0x41, 0xCB,
|
||||
0x89, 0xE8, 0x28, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x68, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 146250000,
|
||||
.conf = {
|
||||
@@ -551,6 +605,33 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
|
||||
0x54, 0x4B, 0x25, 0x03, 0x00, 0x80, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 162000000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x22, 0x01, 0x40, 0x30, 0xD4, 0xCD,
|
||||
0x89, 0xE8, 0xC9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x31, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 164100000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x22, 0x89, 0x49, 0xB0, 0x15, 0xCE,
|
||||
0x8A, 0xF8, 0xCD, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0x2B, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pixel_clock = 196900000,
|
||||
.conf = {
|
||||
0x01, 0xD1, 0x29, 0x1618, 0x418, 0x190, 0xF5, 0xCF,
|
||||
0x8D, 0x168, 0xF5, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
|
||||
0x08, 0x80, 0x09, 0x84, 0x05, 0x02, 0x24, 0x86,
|
||||
0x54, 0xFA, 0x24, 0x03, 0x00, 0x00, 0x01, 0x80,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hdmiphy_config hdmiphy_5433_configs[] = {
|
||||
|
||||
BIN
firmware/edid/1360x768.bin
Normal file
BIN
firmware/edid/1360x768.bin
Normal file
Binary file not shown.
BIN
firmware/edid/1366x768.bin
Normal file
BIN
firmware/edid/1366x768.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
firmware/edid/1600x900.bin
Normal file
BIN
firmware/edid/1600x900.bin
Normal file
Binary file not shown.
BIN
firmware/edid/1920x1200_30hz.bin
Normal file
BIN
firmware/edid/1920x1200_30hz.bin
Normal file
Binary file not shown.
@@ -218,6 +218,10 @@
|
||||
#define CLK_MOUT_BPLL 655
|
||||
#define CLK_MOUT_MX_MSPLL_CCORE 656
|
||||
|
||||
#define CLK_MOUT_EPLL 660
|
||||
#define CLK_MOUT_MAU_EPLL 661
|
||||
#define CLK_MOUT_MAU_EPLL_USER 662
|
||||
|
||||
#define CLK_MOUT_DPLL 700
|
||||
#define CLK_MOUT_SPI1 701
|
||||
#define CLK_DOUT_SPI1 702
|
||||
|
||||
@@ -229,4 +229,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631
|
||||
select SND_SAMSUNG_I2S
|
||||
select SND_SOC_RT5631
|
||||
|
||||
config SND_SOC_ODROID_MAX98090
|
||||
tristate "SoC I2S Audio support for Maxim MAX98090."
|
||||
depends on I2C
|
||||
select SND_SAMSUNG_I2S
|
||||
select SND_SOC_MAX98090
|
||||
select SND_SOC_SPDIF
|
||||
help
|
||||
Say Y if you want to add support for SoC audio for Maxim MAX98090
|
||||
|
||||
endif #SND_SOC_SAMSUNG
|
||||
|
||||
@@ -44,6 +44,7 @@ snd-soc-lowland-objs := lowland.o
|
||||
snd-soc-littlemill-objs := littlemill.o
|
||||
snd-soc-bells-objs := bells.o
|
||||
snd-soc-arndale-rt5631-objs := arndale_rt5631.o
|
||||
snd-soc-odroid-max98090-objs := odroid_max98090.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
|
||||
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
|
||||
@@ -69,3 +70,4 @@ 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_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_ODROID_MAX98090) += snd-soc-odroid-max98090.o
|
||||
|
||||
459
sound/soc/samsung/odroid_max98090.c
Normal file
459
sound/soc/samsung/odroid_max98090.c
Normal file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* odroid_max98090.c
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "i2s.h"
|
||||
#include "i2s-regs.h"
|
||||
|
||||
static int set_audio_clock_heirachy(struct device *card_dev);
|
||||
static inline int clk_set_div(struct clk *c, unsigned long parent_rate, int n)
|
||||
{
|
||||
return clk_set_rate(c, (parent_rate / n));
|
||||
}
|
||||
/*
|
||||
* The initial rate that EPLL will be set to. This is the smallest multiple (4)
|
||||
* of the desired master clock frequency 256 * FS for FS = 44.1khz that can
|
||||
* be generated on both the 5250 and 5420 SoCs.
|
||||
*/
|
||||
static int set_audss_pll_rate(struct device *card_dev, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
struct clk *fout_epll;
|
||||
struct clk *dout_srp, *dout_aud_bus;
|
||||
|
||||
ret = set_audio_clock_heirachy(card_dev);
|
||||
if (ret) {
|
||||
dev_err(card_dev, "failed to set up clock hierarchy (%d)\n",
|
||||
ret);
|
||||
}
|
||||
fout_epll = devm_clk_get(card_dev, "fout_epll");
|
||||
if (IS_ERR(fout_epll)) {
|
||||
dev_err(card_dev, "%s: failed to get fout_epll\n", __func__);
|
||||
return PTR_ERR(fout_epll);
|
||||
}
|
||||
dout_srp = devm_clk_get(card_dev, "dout_srp");
|
||||
if (IS_ERR(dout_srp)) {
|
||||
dev_err(card_dev, "%s: failed to get dout_srp\n", __func__);
|
||||
goto out1;
|
||||
}
|
||||
dout_aud_bus = devm_clk_get(card_dev, "dout_aud_bus");
|
||||
if (IS_ERR(dout_aud_bus)) {
|
||||
dev_err(card_dev, "%s: failed to get dout_aud_bus\n", __func__);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(fout_epll, rate);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "failed to clk_set_rate of fout_epll for audio\n");
|
||||
goto out3;
|
||||
}
|
||||
ret = clk_set_div(dout_srp, rate, 3);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "failed to clk_set_rate of dout_srp for audio\n");
|
||||
goto out3;
|
||||
}
|
||||
ret = clk_set_div(dout_aud_bus, (rate / 4), 3);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "failed to clk_set_rate of dout_aud_bus for audio\n");
|
||||
goto out3;
|
||||
}
|
||||
dev_dbg(card_dev,"%s[%d] : epll=%ld\n",__func__,__LINE__,clk_get_rate(fout_epll));
|
||||
dev_dbg(card_dev,"%s[%d] : dout_srp=%ld\n",__func__,__LINE__,clk_get_rate(dout_srp));
|
||||
dev_dbg(card_dev,"%s[%d] : dout_bus=%ld\n",__func__,__LINE__,clk_get_rate(dout_aud_bus));
|
||||
out3:
|
||||
clk_put(dout_aud_bus);
|
||||
out2:
|
||||
clk_put(dout_srp);
|
||||
out1:
|
||||
clk_put(fout_epll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Audio clock settings are belonged to board specific part. Every
|
||||
* board can set audio source clock setting which is matched with H/W
|
||||
* like this function-'set_audio_clock_heirachy'.
|
||||
*/
|
||||
static int set_audio_clock_heirachy(struct device *card_dev)
|
||||
{
|
||||
struct clk *fout_epll, *mout_sclk_epll;
|
||||
struct clk *mout_mau_epll, *mout_mau_epll_user;
|
||||
struct clk *mout_audss, *mout_i2s;
|
||||
struct clk *mau_epll;
|
||||
int ret = 0;
|
||||
|
||||
fout_epll = devm_clk_get(card_dev, "fout_epll");
|
||||
if (IS_ERR(fout_epll)) {
|
||||
dev_err(card_dev, "%s: Cannot find fout_epll.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
clk_prepare_enable(fout_epll);
|
||||
|
||||
mout_sclk_epll = devm_clk_get(card_dev, "mout_sclk_epll");
|
||||
if (IS_ERR(mout_sclk_epll)) {
|
||||
dev_err(card_dev, "%s: Cannot find mout_sclk_epll.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto out1;
|
||||
}
|
||||
clk_prepare_enable(mout_sclk_epll);
|
||||
|
||||
mout_mau_epll = devm_clk_get(card_dev, "mout_mau_epll");
|
||||
if (IS_ERR(mout_mau_epll)) {
|
||||
dev_err(card_dev,
|
||||
"%s: Cannot find mout_mau_epll clocks.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto out2;
|
||||
}
|
||||
clk_prepare_enable(mout_mau_epll);
|
||||
|
||||
mout_mau_epll_user = devm_clk_get(card_dev, "mout_mau_epll_user");
|
||||
if (IS_ERR(mout_mau_epll_user)) {
|
||||
dev_err(card_dev,
|
||||
"%s: Cannot find mout_mau_epll_user clocks.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto out3;
|
||||
}
|
||||
clk_prepare_enable(mout_mau_epll_user);
|
||||
|
||||
mout_audss = devm_clk_get(card_dev, "mout_audss");
|
||||
if (IS_ERR(mout_audss)) {
|
||||
dev_err(card_dev,
|
||||
"%s: Cannot find mout_audss clocks.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto out4;
|
||||
}
|
||||
clk_prepare_enable(mout_audss);
|
||||
|
||||
mout_i2s = devm_clk_get(card_dev, "mout_i2s");
|
||||
if (IS_ERR(mout_i2s)) {
|
||||
dev_err(card_dev,
|
||||
"%s: Cannot find mout_i2s clocks.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto out5;
|
||||
}
|
||||
clk_prepare_enable(mout_i2s);
|
||||
|
||||
mau_epll = devm_clk_get(card_dev, "mau_epll_clk");
|
||||
if (IS_ERR(mau_epll)) {
|
||||
dev_err(card_dev,
|
||||
"%s: Cannot find mau_epll clocks.\n", __func__);
|
||||
ret = -EINVAL;
|
||||
goto out6;
|
||||
}
|
||||
clk_prepare_enable(mau_epll);
|
||||
|
||||
/* Set audio clock hierarchy for S/PDIF */
|
||||
ret = clk_set_parent(mout_sclk_epll, fout_epll);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "Failed to set parent of epll.\n");
|
||||
goto out7;
|
||||
}
|
||||
ret = clk_set_parent(mout_mau_epll, mout_sclk_epll);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "Failed to set parent of mout_mau_epll.\n");
|
||||
goto out7;
|
||||
}
|
||||
ret = clk_set_parent(mout_mau_epll_user, mout_mau_epll);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "Failed to set parent of epll.\n");
|
||||
goto out7;
|
||||
}
|
||||
ret = clk_set_parent(mout_audss, mout_mau_epll_user);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "Failed to set parent of audss.\n");
|
||||
goto out7;
|
||||
}
|
||||
ret = clk_set_parent(mout_i2s, mout_audss);
|
||||
if (ret < 0) {
|
||||
dev_err(card_dev, "Failed to set parent of mout i2s.\n");
|
||||
goto out7;
|
||||
}
|
||||
out7:
|
||||
clk_put(mau_epll);
|
||||
out6:
|
||||
clk_put(mout_i2s);
|
||||
out5:
|
||||
clk_put(mout_audss);
|
||||
out4:
|
||||
clk_put(mout_mau_epll_user);
|
||||
out3:
|
||||
clk_put(mout_mau_epll);
|
||||
out2:
|
||||
clk_put(mout_sclk_epll);
|
||||
out1:
|
||||
clk_put(fout_epll);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ODROID MAX98090 I2S DAI operations. (Soc master)
|
||||
*/
|
||||
static int odroid_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int bfs, psr, rfs, ret, div=4;
|
||||
unsigned long rclk, sclk;
|
||||
unsigned long pll;
|
||||
struct device *card_dev = substream->pcm->card->dev;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_U24_LE:
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
bfs = 48;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_U16_LE:
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
bfs = 32;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 16000:
|
||||
case 22050:
|
||||
case 24000:
|
||||
case 32000:
|
||||
case 44100:
|
||||
case 48000:
|
||||
case 88200:
|
||||
case 96000:
|
||||
if (bfs == 48)
|
||||
rfs = 384;
|
||||
else
|
||||
rfs = 256;
|
||||
break;
|
||||
case 64000:
|
||||
rfs = 384;
|
||||
break;
|
||||
case 8000:
|
||||
case 11025:
|
||||
case 12000:
|
||||
if (bfs == 48)
|
||||
rfs = 768;
|
||||
else
|
||||
rfs = 512;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rclk = params_rate(params) * rfs;
|
||||
|
||||
switch (rclk) {
|
||||
case 4096000:
|
||||
case 5644800:
|
||||
case 6144000:
|
||||
case 8467200:
|
||||
case 9216000:
|
||||
psr = 8;
|
||||
break;
|
||||
case 8192000:
|
||||
case 11289600:
|
||||
case 12288000:
|
||||
case 16934400:
|
||||
case 18432000:
|
||||
psr = 4;
|
||||
break;
|
||||
case 22579200:
|
||||
case 24576000:
|
||||
case 33868800:
|
||||
case 36864000:
|
||||
psr = 2;
|
||||
break;
|
||||
case 67737600:
|
||||
case 73728000:
|
||||
psr = 1;
|
||||
break;
|
||||
default:
|
||||
dev_err(card_dev, "rclk = %lu is not yet supported!\n", rclk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(card_dev,"%s[%d]: rate=%d, bfs=%d, rfs=%d, psr=%d \n",
|
||||
__func__,__LINE__, params_rate(params), bfs, rfs, psr);
|
||||
|
||||
sclk = rclk * psr;
|
||||
pll = sclk * div;
|
||||
dev_dbg(card_dev,"%s[%d]: rclk=%ld, sclk=%ld, pll=%ld\n",
|
||||
__func__,__LINE__, rclk, sclk, pll);
|
||||
|
||||
ret = set_audss_pll_rate(card_dev, pll);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS);
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_IN);
|
||||
|
||||
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK,
|
||||
0, MOD_OPCLK_PCLK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
|
||||
rclk, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
|
||||
rfs, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops odroid_ops = {
|
||||
.hw_params = odroid_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link odroid_dai[] = {
|
||||
{ /* Primary DAI i/f */
|
||||
.name = "MAX98090 AIF1",
|
||||
.stream_name = "i2s0-sec",
|
||||
.codec_dai_name = "HiFi",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ops = &odroid_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_card odroid_snd = {
|
||||
.name = "odroid-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = odroid_dai,
|
||||
.num_links = ARRAY_SIZE(odroid_dai),
|
||||
};
|
||||
|
||||
static int odroid_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &odroid_snd;
|
||||
struct device_node *i2s_node, *codec_node;
|
||||
const char *name, *codec_dai_name;
|
||||
int i, ret;
|
||||
|
||||
if (!pdev->dev.platform_data && !pdev->dev.of_node) {
|
||||
dev_err(&pdev->dev, "No platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
name = of_get_property(pdev->dev.of_node, "card-name", NULL);
|
||||
if (name)
|
||||
card->name = name;
|
||||
|
||||
i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
"samsung,i2s-controller", 0);
|
||||
if (!i2s_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'i2s-controller' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
codec_node = of_parse_phandle(pdev->dev.of_node,
|
||||
"samsung,audio-codec", 0);
|
||||
if (!codec_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'audio-codec' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
codec_dai_name = of_get_property(pdev->dev.of_node, "codec-dai-name", NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(odroid_dai); i++) {
|
||||
odroid_dai[i].codec_of_node = codec_node;
|
||||
odroid_dai[i].cpu_of_node = i2s_node;
|
||||
odroid_dai[i].platform_of_node = i2s_node;
|
||||
if (codec_dai_name)
|
||||
odroid_dai[i].codec_dai_name = codec_dai_name;
|
||||
}
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = set_audio_clock_heirachy(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to set up clock hierarchy (%d)\n",
|
||||
ret);
|
||||
snd_soc_unregister_card(card);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int odroid_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id odroid_max98090_of_match[] = {
|
||||
{ .compatible = "hardkernel,odroid-max98090", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, samsung_max98090_of_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct platform_driver odroid_audio_driver = {
|
||||
.driver = {
|
||||
.name = "odroid-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = of_match_ptr(odroid_max98090_of_match),
|
||||
#endif
|
||||
},
|
||||
.probe = odroid_audio_probe,
|
||||
.remove = odroid_audio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(odroid_audio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ALSA SoC ODROID MAX98090");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:odroid-audio");
|
||||
Reference in New Issue
Block a user