/* * sound/soc/codecs/si476x.c -- Codec driver for SI476X chips * * Copyright (C) 2012 Innovative Converged Devices(ICD) * Copyright (C) 2013 Andrey Smirnov * * Author: Andrey Smirnov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * */ #include #include #include #include #include #include #include #include #include enum si476x_audio_registers { SI476X_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, }; enum si476x_digital_io_output_format { SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT = 11, SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT = 8, }; #define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0x7 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \ (0x7 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)) #define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0x7e) enum si476x_daudio_formats { SI476X_DAUDIO_MODE_I2S = (0x0 << 1), SI476X_DAUDIO_MODE_DSP_A = (0x6 << 1), SI476X_DAUDIO_MODE_DSP_B = (0x7 << 1), SI476X_DAUDIO_MODE_LEFT_J = (0x8 << 1), SI476X_DAUDIO_MODE_RIGHT_J = (0x9 << 1), SI476X_DAUDIO_MODE_IB = (1 << 5), SI476X_DAUDIO_MODE_IF = (1 << 6), }; enum si476x_pcm_format { SI476X_PCM_FORMAT_S8 = 2, SI476X_PCM_FORMAT_S16_LE = 4, SI476X_PCM_FORMAT_S20_3LE = 5, SI476X_PCM_FORMAT_S24_LE = 6, }; static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("LOUT"), SND_SOC_DAPM_OUTPUT("ROUT"), }; static const struct snd_soc_dapm_route si476x_dapm_routes[] = { { "Capture", NULL, "LOUT" }, { "Capture", NULL, "ROUT" }, }; static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev); int err; u16 format = 0; if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: format |= SI476X_DAUDIO_MODE_DSP_A; break; case SND_SOC_DAIFMT_DSP_B: format |= SI476X_DAUDIO_MODE_DSP_B; break; case SND_SOC_DAIFMT_I2S: format |= SI476X_DAUDIO_MODE_I2S; break; case SND_SOC_DAIFMT_RIGHT_J: format |= SI476X_DAUDIO_MODE_RIGHT_J; break; case SND_SOC_DAIFMT_LEFT_J: format |= SI476X_DAUDIO_MODE_LEFT_J; break; default: return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_NF: format |= SI476X_DAUDIO_MODE_IB; break; default: return -EINVAL; } break; case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_LEFT_J: switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_IF: format |= SI476X_DAUDIO_MODE_IB | SI476X_DAUDIO_MODE_IF; break; case SND_SOC_DAIFMT_IB_NF: format |= SI476X_DAUDIO_MODE_IB; break; case SND_SOC_DAIFMT_NB_IF: format |= SI476X_DAUDIO_MODE_IF; break; default: return -EINVAL; } break; default: return -EINVAL; } si476x_core_lock(core); err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK, format); si476x_core_unlock(core); if (err < 0) { dev_err(codec_dai->codec->dev, "Failed to set output format\n"); return err; } return 0; } static int si476x_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev); int rate, width, err; rate = params_rate(params); if (rate < 32000 || rate > 48000) { dev_err(dai->codec->dev, "Rate: %d is not supported\n", rate); return -EINVAL; } switch (params_width(params)) { case 8: width = SI476X_PCM_FORMAT_S8; break; case 16: width = SI476X_PCM_FORMAT_S16_LE; break; case 20: width = SI476X_PCM_FORMAT_S20_3LE; break; case 24: width = SI476X_PCM_FORMAT_S24_LE; break; default: return -EINVAL; } si476x_core_lock(core); err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE, rate); if (err < 0) { dev_err(dai->codec->dev, "Failed to set sample rate\n"); goto out; } err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT, SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK, (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)); if (err < 0) { dev_err(dai->codec->dev, "Failed to set output width\n"); goto out; } out: si476x_core_unlock(core); return err; } static const struct snd_soc_dai_ops si476x_dai_ops = { .hw_params = si476x_codec_hw_params, .set_fmt = si476x_codec_set_dai_fmt, }; static struct snd_soc_dai_driver si476x_dai = { .name = "si476x-codec", .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE }, .ops = &si476x_dai_ops, }; static struct regmap *si476x_get_regmap(struct device *dev) { return dev_get_regmap(dev->parent, NULL); } static struct snd_soc_codec_driver soc_codec_dev_si476x = { .get_regmap = si476x_get_regmap, .component_driver = { .dapm_widgets = si476x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets), .dapm_routes = si476x_dapm_routes, .num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes), }, }; static int si476x_platform_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_si476x, &si476x_dai, 1); } static int si476x_platform_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; } MODULE_ALIAS("platform:si476x-codec"); static struct platform_driver si476x_platform_driver = { .driver = { .name = "si476x-codec", }, .probe = si476x_platform_probe, .remove = si476x_platform_remove, }; module_platform_driver(si476x_platform_driver); MODULE_AUTHOR("Andrey Smirnov "); MODULE_DESCRIPTION("ASoC Si4761/64 codec driver"); MODULE_LICENSE("GPL"); ck/bcm-nsp.h?id=3c19bd6c52d441893ba19b3418825b27cfa4fd9c'>bcm-nsp.h2148logplain -rw-r--r--bcm21664.h1984logplain -rw-r--r--bcm281xx.h2456logplain -rw-r--r--bcm2835-aux.h635logplain -rw-r--r--bcm2835.h1962logplain -rw-r--r--berlin2.h1034logplain -rw-r--r--berlin2q.h695logplain -rw-r--r--clps711x-clock.h718logplain -rw-r--r--efm32-cmu.h1112logplain -rw-r--r--exynos-audss-clk.h597logplain -rw-r--r--exynos3250.h9083logplain -rw-r--r--exynos4.h8284logplain -rw-r--r--exynos4415.h9828logplain -rw-r--r--exynos5250.h4616logplain -rw-r--r--exynos5260-clk.h14876logplain -rw-r--r--exynos5410.h1689logplain -rw-r--r--exynos5420.h6857logplain -rw-r--r--exynos5433.h45372logplain -rw-r--r--exynos5440.h1141logplain -rw-r--r--exynos7-clk.h5281logplain -rw-r--r--gxbb-aoclkc.h2866logplain -rw-r--r--gxbb-clkc.h592logplain -rw-r--r--hi3516cv300-clock.h1668logplain -rw-r--r--hi3519-clock.h1328logplain -rw-r--r--hi3620-clock.h4496logplain -rw-r--r--hi6220-clock.h4508logplain -rw-r--r--hip04-clock.h1137logplain -rw-r--r--histb-clock.h2012logplain -rw-r--r--hix5hd2-clock.h2415logplain -rw-r--r--imx1-clock.h1055logplain -rw-r--r--imx21-clock.h2461logplain -rw-r--r--imx27-clock.h3494logplain -rw-r--r--imx5-clock.h7212logplain -rw-r--r--imx6qdl-clock.h9593logplain -rw-r--r--imx6sl-clock.h5849logplain -rw-r--r--imx6sx-clock.h9099logplain -rw-r--r--imx6ul-clock.h8203logplain -rw-r--r--imx7d-clock.h15974logplain -rw-r--r--jz4740-cgu.h1028logplain -rw-r--r--jz4780-cgu.h2470logplain -rw-r--r--lpc18xx-ccu.h2134logplain -rw-r--r--lpc18xx-cgu.h1142logplain -rw-r--r--lpc32xx-clock.h1633logplain -rw-r--r--lsi,axm5516-clks.h974logplain -rw-r--r--marvell,mmp2.h2022logplain -rw-r--r--marvell,pxa168.h1654logplain -rw-r--r--marvell,pxa1928.h1535logplain -rw-r--r--marvell,pxa910.h1598logplain -rw-r--r--maxim,max77620.h632logplain -rw-r--r--maxim,max77686.h648logplain -rw-r--r--maxim,max77802.h630logplain -rw-r--r--meson8b-clkc.h523logplain -rw-r--r--microchip,pic32-clock.h1150logplain -rw-r--r--mpc512x-clock.h2236logplain -rw-r--r--mt2701-clk.h13832logplain -rw-r--r--mt8135-clk.h5641logplain -rw-r--r--mt8173-clk.h9293logplain -rw-r--r--oxsemi,ox810se.h1002logplain -rw-r--r--oxsemi,ox820.h1203logplain -rw-r--r--pistachio-clk.h4863logplain -rw-r--r--pxa-clock.h1715logplain -rw-r--r--qcom,gcc-apq8084.h12872logplain -rw-r--r--qcom,gcc-ipq4019.h5423logplain -rw-r--r--qcom,gcc-ipq806x.h8574logplain -rw-r--r--qcom,gcc-mdm9615.h9497logplain -rw-r--r--qcom,gcc-msm8660.h7932logplain -rw-r--r--qcom,gcc-msm8916.h6190logplain -rw-r--r--qcom,gcc-msm8960.h9342logplain -rw-r--r--qcom,gcc-msm8974.h12340logplain -rw-r--r--qcom,gcc-msm8994.h4858logplain -rw-r--r--qcom,gcc-msm8996.h12575logplain -rw-r--r--qcom,lcc-ipq806x.h899logplain -rw-r--r--qcom,lcc-mdm9615.h1701logplain -rw-r--r--qcom,lcc-msm8960.h1616logplain -rw-r--r--qcom,mmcc-apq8084.h5722logplain -rw-r--r--qcom,mmcc-msm8960.h4109logplain -rw-r--r--qcom,mmcc-msm8974.h5223logplain -rw-r--r--qcom,mmcc-msm8996.h9403logplain -rw-r--r--qcom,rpmcc.h2101logplain -rw-r--r--r7s72100-clock.h1218logplain -rw-r--r--r8a73a4-clock.h1596logplain -rw-r--r--r8a7740-clock.h1992logplain -rw-r--r--r8a7743-cpg-mssr.h1269logplain -rw-r--r--r8a7745-cpg-mssr.h1298logplain -rw-r--r--r8a7778-clock.h1855logplain -rw-r--r--r8a7779-clock.h1647logplain -rw-r--r--r8a7790-clock.h4367logplain -rw-r--r--r8a7791-clock.h4388logplain -rw-r--r--r8a7792-clock.h2562logplain -rw-r--r--r8a7793-clock.h4561logplain -rw-r--r--r8a7794-clock.h3679logplain -rw-r--r--r8a7795-cpg-mssr.h1890logplain -rw-r--r--r8a7796-cpg-mssr.h2066logplain -rw-r--r--renesas-cpg-mssr.h542logplain -rw-r--r--rk1108-cru.h6605logplain -rw-r--r--rk3036-cru.h4584logplain -rw-r--r--rk3066a-cru.h1068logplain -rw-r--r--rk3188-cru-common.h6105logplain -rw-r--r--rk3188-cru.h1435logplain