diff --git a/.config b/.config index f832165..10dcb5d 100644 --- a/.config +++ b/.config @@ -1410,8 +1410,15 @@ CONFIG_PACKAGE_gdbserver=m # # I2C support # -# CONFIG_PACKAGE_kmod-i2c-core is not set +CONFIG_PACKAGE_kmod-i2c-core=y +# CONFIG_PACKAGE_kmod-i2c-algo-bit is not set +# CONFIG_PACKAGE_kmod-i2c-algo-pca is not set +# CONFIG_PACKAGE_kmod-i2c-algo-pcf is not set +# CONFIG_PACKAGE_kmod-i2c-gpio is not set # CONFIG_PACKAGE_kmod-i2c-gpio-custom is not set +# CONFIG_PACKAGE_kmod-i2c-mux is not set +CONFIG_PACKAGE_kmod-i2c-ralink=y +# CONFIG_PACKAGE_kmod-i2c-tiny-usb is not set CONFIG_PACKAGE_kmod-kkmoon-motors=y # @@ -1456,7 +1463,7 @@ CONFIG_PACKAGE_kmod-lib-crc-itu-t=y # CONFIG_PACKAGE_kmod-lib-crc7 is not set # CONFIG_PACKAGE_kmod-lib-crc8 is not set # CONFIG_PACKAGE_kmod-lib-lz4 is not set -# CONFIG_PACKAGE_kmod-lib-lzo is not set +CONFIG_PACKAGE_kmod-lib-lzo=y # CONFIG_PACKAGE_kmod-lib-textsearch is not set # CONFIG_PACKAGE_kmod-lib-zlib is not set @@ -1651,7 +1658,7 @@ CONFIG_PACKAGE_kmod-gpio-button-hotplug=y # CONFIG_PACKAGE_kmod-pps-gpio is not set # CONFIG_PACKAGE_kmod-ptp is not set # CONFIG_PACKAGE_kmod-random-core is not set -# CONFIG_PACKAGE_kmod-regmap is not set +CONFIG_PACKAGE_kmod-regmap=y # CONFIG_PACKAGE_kmod-rotary-gpio-custom is not set # CONFIG_PACKAGE_kmod-sdhci is not set # CONFIG_PACKAGE_kmod-serial-8250 is not set @@ -1675,12 +1682,13 @@ CONFIG_PACKAGE_kmod-gpio-button-hotplug=y # # Sound Support # -CONFIG_PACKAGE_kmod-sound-core=m -# CONFIG_PACKAGE_kmod-ac97 is not set +CONFIG_PACKAGE_kmod-sound-core=y +CONFIG_PACKAGE_kmod-ac97=y # CONFIG_PACKAGE_kmod-sound-i8x0 is not set +CONFIG_PACKAGE_kmod-sound-rt5350=y # CONFIG_PACKAGE_kmod-sound-seq is not set # CONFIG_PACKAGE_kmod-sound-soc-ac97 is not set -# CONFIG_PACKAGE_kmod-sound-soc-core is not set +CONFIG_PACKAGE_kmod-sound-soc-core=y CONFIG_PACKAGE_kmod-usb-audio=m # diff --git a/target/linux/ramips/dts/TP-C516W-common.dtsi b/target/linux/ramips/dts/TP-C516W-common.dtsi index 675f83a..368c387 100644 --- a/target/linux/ramips/dts/TP-C516W-common.dtsi +++ b/target/linux/ramips/dts/TP-C516W-common.dtsi @@ -5,6 +5,20 @@ status = "ok"; }; + i2c@900 { + status = "ok"; + }; + + i2s: i2s@a00 { + status = "ok"; + +/* + pinctrl-names = "default"; + pinctrl-0 = <&i2s_gpio_pins>; +*/ + + }; + spi@b00 { pinctrl-names = "default"; pinctrl-0 = <&spi_pins>; @@ -12,13 +26,50 @@ }; + + audio { + compatible = "ralink,rt5350-audio-cjc8988"; + i2s-controller = <&i2s>; + audio-codec = <&codec>; + }; + + codec: codec { + compatible = "wlf,wm8988", "chinaic,cjc8988"; + }; + + pinctrl { + i2s_gpio_pins: i2s { + i2s { + ralink,group = "uartf"; + ralink,function = "gpio i2s"; + }; + }; + + state_default: pinctrl0 { gpio { - ralink,group = "jtag", "rgmii", "mdio", "led", "spi_cs1", "uartf"; + ralink,group = "jtag", "rgmii", "mdio", "led", "spi_cs1"; ralink,function = "gpio"; }; + + /* Do this here as it crosses two functions */ + i2s { + ralink,group = "uartf"; + ralink,function = "gpio i2s"; + }; + }; + +/* + i2s_gpio_pins: i2s { + i2s { + ralink,group = "uartf"; + ralink,function = "gpio i2s"; + }; }; +*/ + + }; gpio-leds { diff --git a/target/linux/ramips/modules.mk b/target/linux/ramips/modules.mk index 673fa61..9088a2e 100644 --- a/target/linux/ramips/modules.mk +++ b/target/linux/ramips/modules.mk @@ -88,3 +88,24 @@ define KernelPackage/sound-mt7620/description endef $(eval $(call KernelPackage,sound-mt7620)) + + +define KernelPackage/sound-rt5350 + TITLE:=RT5350 PCM/I2S Alsa Driver + DEPENDS:=@TARGET_ramips +kmod-sound-soc-core +kmod-regmap + KCONFIG:= \ + CONFIG_SND_MT7620_SOC_I2S \ + CONFIG_SND_RT5350_SOC_WM8988 + FILES:= \ + $(LINUX_DIR)/sound/soc/ralink/snd-soc-mt7620-i2s.ko \ + $(LINUX_DIR)/sound/soc/ralink/snd-soc-rt5350-wm8988.ko \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8988.ko + AUTOLOAD:=$(call AutoLoad,90,snd-soc-wm8960 snd-soc-mt7620-i2s snd-soc-mt7620-wm8960) + $(call AddDepends/sound) +endef + +define KernelPackage/sound-rt5350/description + Alsa modules for ralink i2s controller. +endef + +$(eval $(call KernelPackage,sound-rt5350)) diff --git a/target/linux/ramips/patches-3.18/9998-rt5350-i2s.patch b/target/linux/ramips/patches-3.18/9998-rt5350-i2s.patch new file mode 100644 index 0000000..b7d7754 --- /dev/null +++ b/target/linux/ramips/patches-3.18/9998-rt5350-i2s.patch @@ -0,0 +1,310 @@ +Index: linux-3.18.21/sound/soc/ralink/mt7620-i2s.c +=================================================================== +--- linux-3.18.21.orig/sound/soc/ralink/mt7620-i2s.c ++++ linux-3.18.21/sound/soc/ralink/mt7620-i2s.c +@@ -414,6 +414,7 @@ static int mt7620_i2s_dev_remove(struct + + static const struct of_device_id mt7620_i2s_match[] = { + { .compatible = "ralink,mt7620a-i2s" }, ++ { .compatible = "ralink,rt5350-i2s" }, + {}, + }; + MODULE_DEVICE_TABLE(of, mt7620_i2s_match); +Index: linux-3.18.21/sound/soc/ralink/Kconfig +=================================================================== +--- linux-3.18.21.orig/sound/soc/ralink/Kconfig ++++ linux-3.18.21/sound/soc/ralink/Kconfig +@@ -1,7 +1,7 @@ + config SND_MT7620_SOC_I2S +- depends on SOC_MT7620 && SND_SOC ++ depends on (SOC_RT305X || SOC_MT7620) && SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM +- tristate "SoC Audio (I2S protocol) for Ralink MT7620 SoC" ++ tristate "SoC Audio (I2S protocol) for Ralink RT5350 and MT7620 SoC" + help + Say Y if you want to use I2S protocol and I2S codec on Ingenic MT7620 + based boards. +@@ -13,3 +13,11 @@ config SND_MT7620_SOC_WM8960 + help + Say Y if you want to add support for ASoC audio on the Qi LB60 board + a.k.a Qi Ben NanoNote. ++ ++config SND_RT5350_SOC_WM8988 ++ tristate "SoC Audio support for Ralink WM8988" ++ select SND_MT7620_SOC_I2S ++ select SND_SOC_WM8988 ++ help ++ Say Y if you want to add support for ASoC audio on the Qi LB60 board ++ a.k.a Qi Ben NanoNote. +Index: linux-3.18.21/sound/soc/codecs/wm8988.c +=================================================================== +--- linux-3.18.21.orig/sound/soc/codecs/wm8988.c ++++ linux-3.18.21/sound/soc/codecs/wm8988.c +@@ -942,9 +942,17 @@ static const struct i2c_device_id wm8988 + }; + MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); + ++ ++static const struct of_device_id wm8988_of_match[] = { ++ { .compatible = "wlf,wm8988", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, wm8962_of_match); ++ + static struct i2c_driver wm8988_i2c_driver = { + .driver = { + .name = "wm8988", ++ .of_match_table = wm8988_of_match, + .owner = THIS_MODULE, + }, + .probe = wm8988_i2c_probe, +Index: linux-3.18.21/sound/soc/ralink/Makefile +=================================================================== +--- linux-3.18.21.orig/sound/soc/ralink/Makefile ++++ linux-3.18.21/sound/soc/ralink/Makefile +@@ -9,3 +9,7 @@ obj-$(CONFIG_SND_MT7620_SOC_I2S) += snd- + snd-soc-mt7620-wm8960-objs := mt7620-wm8960.o + + obj-$(CONFIG_SND_MT7620_SOC_WM8960) += snd-soc-mt7620-wm8960.o ++ ++snd-soc-rt5350-wm8988-objs := rt5350-wm8988.o ++ ++obj-$(CONFIG_SND_RT5350_SOC_WM8988) += snd-soc-rt5350-wm8988.o +Index: linux-3.18.21/sound/soc/ralink/rt5350-wm8988.c +=================================================================== +--- /dev/null ++++ linux-3.18.21/sound/soc/ralink/rt5350-wm8988.c +@@ -0,0 +1,233 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * Based on rt5350-sgtl5000.c ++ * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012 Linaro Ltd. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/wm8960.h" ++ ++#define DAI_NAME_SIZE 32 ++ ++struct rt5350_wm8960_data { ++ struct snd_soc_dai_link dai; ++ struct snd_soc_card card; ++ char codec_dai_name[DAI_NAME_SIZE]; ++ char platform_name[DAI_NAME_SIZE]; ++ unsigned int clk_frequency; ++}; ++ ++struct rt5350_priv { ++ struct platform_device *pdev; ++}; ++static struct rt5350_priv card_priv; ++ ++static const struct snd_soc_dapm_widget rt5350_wm8960_dapm_widgets[] = { ++ SND_SOC_DAPM_HP("Headphone Jack", NULL), ++ SND_SOC_DAPM_SPK("Ext Spk", NULL), ++ SND_SOC_DAPM_MIC("AMIC", NULL), ++ SND_SOC_DAPM_MIC("DMIC", NULL), ++}; ++ ++static int sample_rate = 44100; ++static snd_pcm_format_t sample_format = SNDRV_PCM_FORMAT_S16_LE; ++ ++static int rt5350_hifi_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ sample_rate = params_rate(params); ++ sample_format = params_format(params); ++ ++ return 0; ++} ++ ++static struct snd_soc_ops rt5350_hifi_ops = { ++ .hw_params = rt5350_hifi_hw_params, ++}; ++ ++static int rt5350_wm8960_set_bias_level(struct snd_soc_card *card, ++ struct snd_soc_dapm_context *dapm, ++ enum snd_soc_bias_level level) ++{ ++ struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; ++ struct rt5350_priv *priv = &card_priv; ++ struct rt5350_wm8960_data *data = snd_soc_card_get_drvdata(card); ++ struct device *dev = &priv->pdev->dev; ++ int ret; ++ ++ if (dapm->dev != codec_dai->dev) ++ return 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_PREPARE: ++ if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { ++ } ++ break; ++ ++ case SND_SOC_BIAS_STANDBY: ++ if (dapm->bias_level == SND_SOC_BIAS_PREPARE) { ++ ret = snd_soc_dai_set_sysclk(codec_dai, ++ WM8960_SYSCLK_MCLK, data->clk_frequency, ++ SND_SOC_CLOCK_IN); ++ if (ret < 0) { ++ dev_err(dev, ++ "failed to switch away from FLL: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rt5350_wm8960_late_probe(struct snd_soc_card *card) ++{ ++ struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; ++ struct rt5350_priv *priv = &card_priv; ++ struct rt5350_wm8960_data *data = snd_soc_card_get_drvdata(card); ++ struct device *dev = &priv->pdev->dev; ++ int ret; ++ ++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8960_SYSCLK_MCLK, ++ data->clk_frequency, SND_SOC_CLOCK_IN); ++ if (ret < 0) ++ dev_err(dev, "failed to set sysclk in %s\n", __func__); ++ ++ return ret; ++} ++ ++static int rt5350_wm8960_probe(struct platform_device *pdev) ++{ ++ struct device_node *i2s_np, *codec_np; ++ struct platform_device *i2s_pdev; ++ struct rt5350_priv *priv = &card_priv; ++ struct i2c_client *codec_dev; ++ struct rt5350_wm8960_data *data; ++ int ret; ++ ++ priv->pdev = pdev; ++ ++ i2s_np = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0); ++ codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); ++ if (!i2s_np || !codec_np) { ++ dev_err(&pdev->dev, "phandle missing or invalid\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ i2s_pdev = of_find_device_by_node(i2s_np); ++ if (!i2s_pdev) { ++ dev_err(&pdev->dev, "failed to find SSI platform device\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ codec_dev = of_find_i2c_device_by_node(codec_np); ++ if (!codec_dev || !codec_dev->dev.driver) { ++ dev_err(&pdev->dev, "failed to find codec platform device\n"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ data->clk_frequency = 12000000; ++ data->dai.name = "HiFi"; ++ data->dai.stream_name = "HiFi"; ++ data->dai.codec_dai_name = "wm8960-hifi"; ++ data->dai.codec_of_node = codec_np; ++ data->dai.cpu_dai_name = dev_name(&i2s_pdev->dev); ++ data->dai.platform_of_node = i2s_np; ++ data->dai.ops = &rt5350_hifi_ops; ++ data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM; ++ ++ data->card.dev = &pdev->dev; ++ ret = snd_soc_of_parse_card_name(&data->card, "model"); ++ if (ret) ++ goto fail; ++ ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); ++ if (ret) ++ goto fail; ++ data->card.num_links = 1; ++ data->card.dai_link = &data->dai; ++ data->card.dapm_widgets = rt5350_wm8960_dapm_widgets; ++ data->card.num_dapm_widgets = ARRAY_SIZE(rt5350_wm8960_dapm_widgets); ++ ++ data->card.late_probe = rt5350_wm8960_late_probe; ++ data->card.set_bias_level = rt5350_wm8960_set_bias_level; ++ ++ platform_set_drvdata(pdev, &data->card); ++ snd_soc_card_set_drvdata(&data->card, data); ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, &data->card); ++ if (ret) { ++ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); ++ goto fail; ++ } ++ ++ of_node_put(i2s_np); ++ of_node_put(codec_np); ++ ++ return 0; ++fail: ++ if (i2s_np) ++ of_node_put(i2s_np); ++ if (codec_np) ++ of_node_put(codec_np); ++ ++ return ret; ++} ++ ++static int rt5350_wm8960_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id rt5350_wm8960_dt_ids[] = { ++ { .compatible = "ralink,rt5350-audio-cjc8988", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, rt5350_wm8960_dt_ids); ++ ++static struct platform_driver rt5350_wm8960_driver = { ++ .driver = { ++ .name = "rt5350-wm8960", ++ .owner = THIS_MODULE, ++ .pm = &snd_soc_pm_ops, ++ .of_match_table = rt5350_wm8960_dt_ids, ++ }, ++ .probe = rt5350_wm8960_probe, ++ .remove = rt5350_wm8960_remove, ++}; ++module_platform_driver(rt5350_wm8960_driver); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("Freescale i.MX WM8962 ASoC machine driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:rt5350-wm8962");