···4455Required properties:6677-- compatible : "qcom,lpass-cpu"77+- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"88- clocks : Must contain an entry for each entry in clock-names.99- clock-names : A list which must include the following entries:1010 * "ahbix-clk"1111 * "mi2s-osr-clk"1212 * "mi2s-bit-clk"1313+ : required clocks for "qcom,lpass-cpu-apq8016"1414+ * "ahbix-clk"1515+ * "mi2s-bit-clk0"1616+ * "mi2s-bit-clk1"1717+ * "mi2s-bit-clk2"1818+ * "mi2s-bit-clk3"1919+ * "pcnoc-mport-clk"2020+ * "pcnoc-sway-clk"2121+1322- interrupts : Must contain an entry for each entry in1423 interrupt-names.1524- interrupt-names : A list which must include the following entries:···3021- reg : Must contain an address for each entry in reg-names.3122- reg-names : A list which must include the following entries:3223 * "lpass-lpaif"2424+2525+33263427Optional properties:3528
···23012301 /* register an audio interrupt */23022302 ret = request_threaded_irq(client->irq, NULL,23032303 max98095_report_jack,23042304- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,23052305- "max98095", codec);23042304+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |23052305+ IRQF_ONESHOT, "max98095", codec);23062306 if (ret) {23072307 dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);23082308 goto err_access;
+3-2
sound/soc/omap/Kconfig
···100100101101config SND_OMAP_SOC_OMAP_ABE_TWL6040102102 tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"103103- depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST)103103+ depends on TWL6040_CORE && SND_OMAP_SOC104104+ depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST104105 select SND_OMAP_SOC_DMIC105106 select SND_OMAP_SOC_MCPDM106107 select SND_SOC_TWL6040107108 select SND_SOC_DMIC108108- select COMMON_CLK_PALMAS if MFD_PALMAS109109+ select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS)109110 help110111 Say Y if you want to add support for SoC audio on OMAP boards using111112 ABE and twl6040 codec. This driver currently supports:
···6677config SND_SOC_LPASS_CPU88 tristate99- depends on SND_SOC_QCOM109 select REGMAP_MMIO11101211config SND_SOC_LPASS_PLATFORM1312 tristate1414- depends on SND_SOC_QCOM1513 select REGMAP_MMIO1414+1515+config SND_SOC_LPASS_IPQ806X1616+ tristate1717+ depends on SND_SOC_QCOM1818+ select SND_SOC_LPASS_CPU1919+ select SND_SOC_LPASS_PLATFORM2020+2121+config SND_SOC_LPASS_APQ80162222+ tristate2323+ depends on SND_SOC_QCOM2424+ select SND_SOC_LPASS_CPU2525+ select SND_SOC_LPASS_PLATFORM16261727config SND_SOC_STORM1828 tristate "ASoC I2S support for Storm boards"1919- depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST2020- select SND_SOC_LPASS_CPU2121- select SND_SOC_LPASS_PLATFORM2929+ depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST)3030+ select SND_SOC_LPASS_IPQ806X2231 select SND_SOC_MAX98357A2332 help2433 Say Y or M if you want add support for SoC audio on the
···11+/*22+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 and66+ * only version 2 as published by the Free Software Foundation.77+ *88+ * This program is distributed in the hope that it will be useful,99+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1010+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1111+ * GNU General Public License for more details.1212+ *1313+ * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS1414+ *1515+ */1616+1717+1818+#include <linux/clk.h>1919+#include <linux/device.h>2020+#include <linux/err.h>2121+#include <linux/kernel.h>2222+#include <linux/module.h>2323+#include <linux/of.h>2424+#include <linux/platform_device.h>2525+#include <sound/pcm.h>2626+#include <sound/pcm_params.h>2727+#include <sound/soc.h>2828+#include <sound/soc-dai.h>2929+3030+#include <dt-bindings/sound/apq8016-lpass.h>3131+#include "lpass-lpaif-reg.h"3232+#include "lpass.h"3333+3434+static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {3535+ [MI2S_PRIMARY] = {3636+ .id = MI2S_PRIMARY,3737+ .name = "Primary MI2S",3838+ .playback = {3939+ .stream_name = "Primary Playback",4040+ .formats = SNDRV_PCM_FMTBIT_S16 |4141+ SNDRV_PCM_FMTBIT_S24 |4242+ SNDRV_PCM_FMTBIT_S32,4343+ .rates = SNDRV_PCM_RATE_8000 |4444+ SNDRV_PCM_RATE_16000 |4545+ SNDRV_PCM_RATE_32000 |4646+ SNDRV_PCM_RATE_48000 |4747+ SNDRV_PCM_RATE_96000,4848+ .rate_min = 8000,4949+ .rate_max = 96000,5050+ .channels_min = 1,5151+ .channels_max = 8,5252+ },5353+ .probe = &asoc_qcom_lpass_cpu_dai_probe,5454+ .ops = &asoc_qcom_lpass_cpu_dai_ops,5555+ },5656+ [MI2S_SECONDARY] = {5757+ .id = MI2S_SECONDARY,5858+ .name = "Secondary MI2S",5959+ .playback = {6060+ .stream_name = "Secondary Playback",6161+ .formats = SNDRV_PCM_FMTBIT_S16 |6262+ SNDRV_PCM_FMTBIT_S24 |6363+ SNDRV_PCM_FMTBIT_S32,6464+ .rates = SNDRV_PCM_RATE_8000 |6565+ SNDRV_PCM_RATE_16000 |6666+ SNDRV_PCM_RATE_32000 |6767+ SNDRV_PCM_RATE_48000 |6868+ SNDRV_PCM_RATE_96000,6969+ .rate_min = 8000,7070+ .rate_max = 96000,7171+ .channels_min = 1,7272+ .channels_max = 8,7373+ },7474+ .probe = &asoc_qcom_lpass_cpu_dai_probe,7575+ .ops = &asoc_qcom_lpass_cpu_dai_ops,7676+ },7777+ [MI2S_TERTIARY] = {7878+ .id = MI2S_TERTIARY,7979+ .name = "Tertiary MI2S",8080+ .capture = {8181+ .stream_name = "Tertiary Capture",8282+ .formats = SNDRV_PCM_FMTBIT_S16 |8383+ SNDRV_PCM_FMTBIT_S24 |8484+ SNDRV_PCM_FMTBIT_S32,8585+ .rates = SNDRV_PCM_RATE_8000 |8686+ SNDRV_PCM_RATE_16000 |8787+ SNDRV_PCM_RATE_32000 |8888+ SNDRV_PCM_RATE_48000 |8989+ SNDRV_PCM_RATE_96000,9090+ .rate_min = 8000,9191+ .rate_max = 96000,9292+ .channels_min = 1,9393+ .channels_max = 8,9494+ },9595+ .probe = &asoc_qcom_lpass_cpu_dai_probe,9696+ .ops = &asoc_qcom_lpass_cpu_dai_ops,9797+ },9898+ [MI2S_QUATERNARY] = {9999+ .id = MI2S_QUATERNARY,100100+ .name = "Quatenary MI2S",101101+ .playback = {102102+ .stream_name = "Quatenary Playback",103103+ .formats = SNDRV_PCM_FMTBIT_S16 |104104+ SNDRV_PCM_FMTBIT_S24 |105105+ SNDRV_PCM_FMTBIT_S32,106106+ .rates = SNDRV_PCM_RATE_8000 |107107+ SNDRV_PCM_RATE_16000 |108108+ SNDRV_PCM_RATE_32000 |109109+ SNDRV_PCM_RATE_48000 |110110+ SNDRV_PCM_RATE_96000,111111+ .rate_min = 8000,112112+ .rate_max = 96000,113113+ .channels_min = 1,114114+ .channels_max = 8,115115+ },116116+ .capture = {117117+ .stream_name = "Quatenary Capture",118118+ .formats = SNDRV_PCM_FMTBIT_S16 |119119+ SNDRV_PCM_FMTBIT_S24 |120120+ SNDRV_PCM_FMTBIT_S32,121121+ .rates = SNDRV_PCM_RATE_8000 |122122+ SNDRV_PCM_RATE_16000 |123123+ SNDRV_PCM_RATE_32000 |124124+ SNDRV_PCM_RATE_48000 |125125+ SNDRV_PCM_RATE_96000,126126+ .rate_min = 8000,127127+ .rate_max = 96000,128128+ .channels_min = 1,129129+ .channels_max = 8,130130+ },131131+ .probe = &asoc_qcom_lpass_cpu_dai_probe,132132+ .ops = &asoc_qcom_lpass_cpu_dai_ops,133133+ },134134+};135135+136136+static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)137137+{138138+ struct lpass_variant *v = drvdata->variant;139139+ int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,140140+ v->rdma_channels);141141+142142+ if (chan >= v->rdma_channels)143143+ return -EBUSY;144144+145145+ set_bit(chan, &drvdata->rdma_ch_bit_map);146146+147147+ return chan;148148+}149149+150150+static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)151151+{152152+ clear_bit(chan, &drvdata->rdma_ch_bit_map);153153+154154+ return 0;155155+}156156+157157+static int apq8016_lpass_init(struct platform_device *pdev)158158+{159159+ struct lpass_data *drvdata = platform_get_drvdata(pdev);160160+ struct device *dev = &pdev->dev;161161+ int ret;162162+163163+ drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");164164+ if (IS_ERR(drvdata->pcnoc_mport_clk)) {165165+ dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n",166166+ __func__, PTR_ERR(drvdata->pcnoc_mport_clk));167167+ return PTR_ERR(drvdata->pcnoc_mport_clk);168168+ }169169+170170+ ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);171171+ if (ret) {172172+ dev_err(&pdev->dev, "%s() Error enabling pcnoc-mport-clk: %d\n",173173+ __func__, ret);174174+ return ret;175175+ }176176+177177+ drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");178178+ if (IS_ERR(drvdata->pcnoc_sway_clk)) {179179+ dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n",180180+ __func__, PTR_ERR(drvdata->pcnoc_sway_clk));181181+ return PTR_ERR(drvdata->pcnoc_sway_clk);182182+ }183183+184184+ ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);185185+ if (ret) {186186+ dev_err(&pdev->dev, "%s() Error enabling pcnoc_sway_clk: %d\n",187187+ __func__, ret);188188+ return ret;189189+ }190190+191191+ return 0;192192+}193193+194194+static int apq8016_lpass_exit(struct platform_device *pdev)195195+{196196+ struct lpass_data *drvdata = platform_get_drvdata(pdev);197197+198198+ clk_disable_unprepare(drvdata->pcnoc_mport_clk);199199+ clk_disable_unprepare(drvdata->pcnoc_sway_clk);200200+201201+ return 0;202202+}203203+204204+205205+static struct lpass_variant apq8016_data = {206206+ .i2sctrl_reg_base = 0x1000,207207+ .i2sctrl_reg_stride = 0x1000,208208+ .i2s_ports = 4,209209+ .irq_reg_base = 0x6000,210210+ .irq_reg_stride = 0x1000,211211+ .irq_ports = 3,212212+ .rdma_reg_base = 0x8400,213213+ .rdma_reg_stride = 0x1000,214214+ .rdma_channels = 2,215215+ .rdmactl_audif_start = 1,216216+ .dai_driver = apq8016_lpass_cpu_dai_driver,217217+ .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),218218+ .init = apq8016_lpass_init,219219+ .exit = apq8016_lpass_exit,220220+ .alloc_dma_channel = apq8016_lpass_alloc_dma_channel,221221+ .free_dma_channel = apq8016_lpass_free_dma_channel,222222+};223223+224224+static const struct of_device_id apq8016_lpass_cpu_device_id[] = {225225+ { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },226226+ {}227227+};228228+MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);229229+230230+static struct platform_driver apq8016_lpass_cpu_platform_driver = {231231+ .driver = {232232+ .name = "apq8016-lpass-cpu",233233+ .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id),234234+ },235235+ .probe = asoc_qcom_lpass_cpu_platform_probe,236236+ .remove = asoc_qcom_lpass_cpu_platform_remove,237237+};238238+module_platform_driver(apq8016_lpass_cpu_platform_driver);239239+240240+MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");241241+MODULE_LICENSE("GPL v2");242242+
+126-112
sound/soc/qcom/lpass-cpu.c
···1414 */15151616#include <linux/clk.h>1717-#include <linux/compiler.h>1818-#include <linux/device.h>1919-#include <linux/err.h>2020-#include <linux/ioport.h>2117#include <linux/kernel.h>2222-#include <linux/mod_devicetable.h>2318#include <linux/module.h>2419#include <linux/of.h>2020+#include <linux/of_device.h>2521#include <linux/platform_device.h>2622#include <sound/pcm.h>2723#include <sound/pcm_params.h>2824#include <linux/regmap.h>2925#include <sound/soc.h>3026#include <sound/soc-dai.h>3131-#include "lpass-lpaif-ipq806x.h"2727+#include "lpass-lpaif-reg.h"3228#include "lpass.h"33293430static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,···3337 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);3438 int ret;35393636- ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);4040+ if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))4141+ return 0;4242+4343+ ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);3744 if (ret)3845 dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",3946 __func__, freq, ret);···5051 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);5152 int ret;52535353- ret = clk_prepare_enable(drvdata->mi2s_osr_clk);5454- if (ret) {5555- dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",5656- __func__, ret);5757- return ret;5454+ if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {5555+ ret = clk_prepare_enable(5656+ drvdata->mi2s_osr_clk[dai->driver->id]);5757+ if (ret) {5858+ dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",5959+ __func__, ret);6060+ return ret;6161+ }5862 }59636060- ret = clk_prepare_enable(drvdata->mi2s_bit_clk);6464+ ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);6165 if (ret) {6266 dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",6367 __func__, ret);6464- clk_disable_unprepare(drvdata->mi2s_osr_clk);6868+ if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))6969+ clk_disable_unprepare(7070+ drvdata->mi2s_osr_clk[dai->driver->id]);6571 return ret;6672 }6773···7874{7975 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);80768181- clk_disable_unprepare(drvdata->mi2s_bit_clk);8282- clk_disable_unprepare(drvdata->mi2s_osr_clk);7777+ clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);7878+7979+ if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))8080+ clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);8381}84828583static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,···148142 }149143150144 ret = regmap_write(drvdata->lpaif_map,151151- LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval);145145+ LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),146146+ regval);152147 if (ret) {153148 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",154149 __func__, ret);155150 return ret;156151 }157152158158- ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2);153153+ ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],154154+ rate * bitwidth * 2);159155 if (ret) {160156 dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",161157 __func__, rate * bitwidth * 2, ret);···174166 int ret;175167176168 ret = regmap_write(drvdata->lpaif_map,177177- LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);169169+ LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),170170+ 0);178171 if (ret)179172 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",180173 __func__, ret);···190181 int ret;191182192183 ret = regmap_update_bits(drvdata->lpaif_map,193193- LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),184184+ LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),194185 LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);195186 if (ret)196187 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",···210201 case SNDRV_PCM_TRIGGER_RESUME:211202 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:212203 ret = regmap_update_bits(drvdata->lpaif_map,213213- LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),204204+ LPAIF_I2SCTL_REG(drvdata->variant,205205+ dai->driver->id),214206 LPAIF_I2SCTL_SPKEN_MASK,215207 LPAIF_I2SCTL_SPKEN_ENABLE);216208 if (ret)···222212 case SNDRV_PCM_TRIGGER_SUSPEND:223213 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:224214 ret = regmap_update_bits(drvdata->lpaif_map,225225- LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),215215+ LPAIF_I2SCTL_REG(drvdata->variant,216216+ dai->driver->id),226217 LPAIF_I2SCTL_SPKEN_MASK,227218 LPAIF_I2SCTL_SPKEN_DISABLE);228219 if (ret)···235224 return ret;236225}237226238238-static struct snd_soc_dai_ops lpass_cpu_dai_ops = {227227+struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {239228 .set_sysclk = lpass_cpu_daiops_set_sysclk,240229 .startup = lpass_cpu_daiops_startup,241230 .shutdown = lpass_cpu_daiops_shutdown,···244233 .prepare = lpass_cpu_daiops_prepare,245234 .trigger = lpass_cpu_daiops_trigger,246235};236236+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);247237248248-static int lpass_cpu_dai_probe(struct snd_soc_dai *dai)238238+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)249239{250240 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);251241 int ret;252242253243 /* ensure audio hardware is disabled */254244 ret = regmap_write(drvdata->lpaif_map,255255- LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);245245+ LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);256246 if (ret)257247 dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",258248 __func__, ret);259249260250 return ret;261251}262262-263263-static struct snd_soc_dai_driver lpass_cpu_dai_driver = {264264- .playback = {265265- .stream_name = "lpass-cpu-playback",266266- .formats = SNDRV_PCM_FMTBIT_S16 |267267- SNDRV_PCM_FMTBIT_S24 |268268- SNDRV_PCM_FMTBIT_S32,269269- .rates = SNDRV_PCM_RATE_8000 |270270- SNDRV_PCM_RATE_16000 |271271- SNDRV_PCM_RATE_32000 |272272- SNDRV_PCM_RATE_48000 |273273- SNDRV_PCM_RATE_96000,274274- .rate_min = 8000,275275- .rate_max = 96000,276276- .channels_min = 1,277277- .channels_max = 8,278278- },279279- .probe = &lpass_cpu_dai_probe,280280- .ops = &lpass_cpu_dai_ops,281281-};252252+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);282253283254static const struct snd_soc_component_driver lpass_cpu_comp_driver = {284255 .name = "lpass-cpu",···268275269276static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)270277{278278+ struct lpass_data *drvdata = dev_get_drvdata(dev);279279+ struct lpass_variant *v = drvdata->variant;271280 int i;272281273273- for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)274274- if (reg == LPAIF_I2SCTL_REG(i))282282+ for (i = 0; i < v->i2s_ports; ++i)283283+ if (reg == LPAIF_I2SCTL_REG(v, i))275284 return true;276285277277- for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {278278- if (reg == LPAIF_IRQEN_REG(i))286286+ for (i = 0; i < v->irq_ports; ++i) {287287+ if (reg == LPAIF_IRQEN_REG(v, i))279288 return true;280280- if (reg == LPAIF_IRQCLEAR_REG(i))289289+ if (reg == LPAIF_IRQCLEAR_REG(v, i))281290 return true;282291 }283292284284- for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {285285- if (reg == LPAIF_RDMACTL_REG(i))293293+ for (i = 0; i < v->rdma_channels; ++i) {294294+ if (reg == LPAIF_RDMACTL_REG(v, i))286295 return true;287287- if (reg == LPAIF_RDMABASE_REG(i))296296+ if (reg == LPAIF_RDMABASE_REG(v, i))288297 return true;289289- if (reg == LPAIF_RDMABUFF_REG(i))298298+ if (reg == LPAIF_RDMABUFF_REG(v, i))290299 return true;291291- if (reg == LPAIF_RDMAPER_REG(i))300300+ if (reg == LPAIF_RDMAPER_REG(v, i))292301 return true;293302 }294303···299304300305static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)301306{307307+ struct lpass_data *drvdata = dev_get_drvdata(dev);308308+ struct lpass_variant *v = drvdata->variant;302309 int i;303310304304- for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)305305- if (reg == LPAIF_I2SCTL_REG(i))311311+ for (i = 0; i < v->i2s_ports; ++i)312312+ if (reg == LPAIF_I2SCTL_REG(v, i))306313 return true;307314308308- for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {309309- if (reg == LPAIF_IRQEN_REG(i))315315+ for (i = 0; i < v->irq_ports; ++i) {316316+ if (reg == LPAIF_IRQEN_REG(v, i))310317 return true;311311- if (reg == LPAIF_IRQSTAT_REG(i))318318+ if (reg == LPAIF_IRQSTAT_REG(v, i))312319 return true;313320 }314321315315- for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {316316- if (reg == LPAIF_RDMACTL_REG(i))322322+ for (i = 0; i < v->rdma_channels; ++i) {323323+ if (reg == LPAIF_RDMACTL_REG(v, i))317324 return true;318318- if (reg == LPAIF_RDMABASE_REG(i))325325+ if (reg == LPAIF_RDMABASE_REG(v, i))319326 return true;320320- if (reg == LPAIF_RDMABUFF_REG(i))327327+ if (reg == LPAIF_RDMABUFF_REG(v, i))321328 return true;322322- if (reg == LPAIF_RDMACURR_REG(i))329329+ if (reg == LPAIF_RDMACURR_REG(v, i))323330 return true;324324- if (reg == LPAIF_RDMAPER_REG(i))331331+ if (reg == LPAIF_RDMAPER_REG(v, i))325332 return true;326333 }327334···332335333336static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)334337{338338+ struct lpass_data *drvdata = dev_get_drvdata(dev);339339+ struct lpass_variant *v = drvdata->variant;335340 int i;336341337337- for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i)338338- if (reg == LPAIF_IRQSTAT_REG(i))342342+ for (i = 0; i < v->irq_ports; ++i)343343+ if (reg == LPAIF_IRQSTAT_REG(v, i))339344 return true;340345341341- for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i)342342- if (reg == LPAIF_RDMACURR_REG(i))346346+ for (i = 0; i < v->rdma_channels; ++i)347347+ if (reg == LPAIF_RDMACURR_REG(v, i))343348 return true;344349345350 return false;346351}347352348348-static const struct regmap_config lpass_cpu_regmap_config = {353353+static struct regmap_config lpass_cpu_regmap_config = {349354 .reg_bits = 32,350355 .reg_stride = 4,351356 .val_bits = 32,352352- .max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX),353357 .writeable_reg = lpass_cpu_regmap_writeable,354358 .readable_reg = lpass_cpu_regmap_readable,355359 .volatile_reg = lpass_cpu_regmap_volatile,356360 .cache_type = REGCACHE_FLAT,357361};358362359359-static int lpass_cpu_platform_probe(struct platform_device *pdev)363363+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)360364{361365 struct lpass_data *drvdata;362366 struct device_node *dsp_of_node;363367 struct resource *res;364364- int ret;368368+ struct lpass_variant *variant;369369+ struct device *dev = &pdev->dev;370370+ const struct of_device_id *match;371371+ char clk_name[16];372372+ int ret, i, dai_id;365373366374 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);367375 if (dsp_of_node) {···381379 return -ENOMEM;382380 platform_set_drvdata(pdev, drvdata);383381382382+ match = of_match_device(dev->driver->of_match_table, dev);383383+ if (!match || !match->data)384384+ return -EINVAL;385385+386386+ drvdata->variant = (struct lpass_variant *)match->data;387387+ variant = drvdata->variant;388388+384389 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");385385- if (!res) {386386- dev_err(&pdev->dev, "%s() error getting resource\n", __func__);387387- return -ENODEV;388388- }389390390391 drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);391392 if (IS_ERR((void const __force *)drvdata->lpaif)) {···398393 return PTR_ERR((void const __force *)drvdata->lpaif);399394 }400395396396+ lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,397397+ variant->rdma_channels);398398+401399 drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,402400 &lpass_cpu_regmap_config);403401 if (IS_ERR(drvdata->lpaif_map)) {···409401 return PTR_ERR(drvdata->lpaif_map);410402 }411403412412- drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");413413- if (IS_ERR(drvdata->mi2s_osr_clk)) {414414- dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",415415- __func__, PTR_ERR(drvdata->mi2s_osr_clk));416416- return PTR_ERR(drvdata->mi2s_osr_clk);417417- }404404+ if (variant->init)405405+ variant->init(pdev);418406419419- drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");420420- if (IS_ERR(drvdata->mi2s_bit_clk)) {421421- dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n",422422- __func__, PTR_ERR(drvdata->mi2s_bit_clk));423423- return PTR_ERR(drvdata->mi2s_bit_clk);407407+ for (i = 0; i < variant->num_dai; i++) {408408+ dai_id = variant->dai_driver[i].id;409409+ if (variant->num_dai > 1)410410+ sprintf(clk_name, "mi2s-osr-clk%d", i);411411+ else412412+ sprintf(clk_name, "mi2s-osr-clk");413413+414414+ drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,415415+ clk_name);416416+ if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {417417+ dev_warn(&pdev->dev,418418+ "%s() error getting mi2s-osr-clk: %ld\n",419419+ __func__,420420+ PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));421421+ }422422+423423+ if (variant->num_dai > 1)424424+ sprintf(clk_name, "mi2s-bit-clk%d", i);425425+ else426426+ sprintf(clk_name, "mi2s-bit-clk");427427+428428+ drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,429429+ clk_name);430430+ if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {431431+ dev_err(&pdev->dev,432432+ "%s() error getting mi2s-bit-clk: %ld\n",433433+ __func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));434434+ return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);435435+ }424436 }425437426438 drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");···467439 }468440469441 ret = devm_snd_soc_register_component(&pdev->dev,470470- &lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1);442442+ &lpass_cpu_comp_driver,443443+ variant->dai_driver,444444+ variant->num_dai);471445 if (ret) {472446 dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",473447 __func__, ret);···489459 clk_disable_unprepare(drvdata->ahbix_clk);490460 return ret;491461}462462+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);492463493493-static int lpass_cpu_platform_remove(struct platform_device *pdev)464464+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)494465{495466 struct lpass_data *drvdata = platform_get_drvdata(pdev);467467+468468+ if (drvdata->variant->exit)469469+ drvdata->variant->exit(pdev);496470497471 clk_disable_unprepare(drvdata->ahbix_clk);498472499473 return 0;500474}501501-502502-#ifdef CONFIG_OF503503-static const struct of_device_id lpass_cpu_device_id[] = {504504- { .compatible = "qcom,lpass-cpu" },505505- {}506506-};507507-MODULE_DEVICE_TABLE(of, lpass_cpu_device_id);508508-#endif509509-510510-static struct platform_driver lpass_cpu_platform_driver = {511511- .driver = {512512- .name = "lpass-cpu",513513- .of_match_table = of_match_ptr(lpass_cpu_device_id),514514- },515515- .probe = lpass_cpu_platform_probe,516516- .remove = lpass_cpu_platform_remove,517517-};518518-module_platform_driver(lpass_cpu_platform_driver);519519-520520-MODULE_DESCRIPTION("QTi LPASS CPU Driver");521521-MODULE_LICENSE("GPL v2");475475+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
+109
sound/soc/qcom/lpass-ipq806x.c
···11+/*22+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 and66+ * only version 2 as published by the Free Software Foundation.77+ *88+ * This program is distributed in the hope that it will be useful,99+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1010+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1111+ * GNU General Public License for more details.1212+ *1313+ * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS1414+ * Splited out the IPQ8064 soc specific from lpass-cpu.c1515+ */1616+1717+#include <linux/clk.h>1818+#include <linux/device.h>1919+#include <linux/err.h>2020+#include <linux/kernel.h>2121+#include <linux/module.h>2222+#include <linux/of.h>2323+#include <linux/platform_device.h>2424+#include <sound/pcm.h>2525+#include <sound/soc.h>2626+#include <sound/soc-dai.h>2727+2828+#include "lpass-lpaif-reg.h"2929+#include "lpass.h"3030+3131+enum lpaif_i2s_ports {3232+ IPQ806X_LPAIF_I2S_PORT_CODEC_SPK,3333+ IPQ806X_LPAIF_I2S_PORT_CODEC_MIC,3434+ IPQ806X_LPAIF_I2S_PORT_SEC_SPK,3535+ IPQ806X_LPAIF_I2S_PORT_SEC_MIC,3636+ IPQ806X_LPAIF_I2S_PORT_MI2S,3737+};3838+3939+enum lpaif_dma_channels {4040+ IPQ806X_LPAIF_RDMA_CHAN_MI2S,4141+ IPQ806X_LPAIF_RDMA_CHAN_PCM0,4242+ IPQ806X_LPAIF_RDMA_CHAN_PCM1,4343+};4444+4545+static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {4646+ .id = IPQ806X_LPAIF_I2S_PORT_MI2S,4747+ .playback = {4848+ .stream_name = "lpass-cpu-playback",4949+ .formats = SNDRV_PCM_FMTBIT_S16 |5050+ SNDRV_PCM_FMTBIT_S24 |5151+ SNDRV_PCM_FMTBIT_S32,5252+ .rates = SNDRV_PCM_RATE_8000 |5353+ SNDRV_PCM_RATE_16000 |5454+ SNDRV_PCM_RATE_32000 |5555+ SNDRV_PCM_RATE_48000 |5656+ SNDRV_PCM_RATE_96000,5757+ .rate_min = 8000,5858+ .rate_max = 96000,5959+ .channels_min = 1,6060+ .channels_max = 8,6161+ },6262+ .probe = &asoc_qcom_lpass_cpu_dai_probe,6363+ .ops = &asoc_qcom_lpass_cpu_dai_ops,6464+};6565+6666+static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)6767+{6868+ return IPQ806X_LPAIF_RDMA_CHAN_MI2S;6969+}7070+7171+static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)7272+{7373+ return 0;7474+}7575+7676+struct lpass_variant ipq806x_data = {7777+ .i2sctrl_reg_base = 0x0010,7878+ .i2sctrl_reg_stride = 0x04,7979+ .i2s_ports = 5,8080+ .irq_reg_base = 0x3000,8181+ .irq_reg_stride = 0x1000,8282+ .irq_ports = 3,8383+ .rdma_reg_base = 0x6000,8484+ .rdma_reg_stride = 0x1000,8585+ .rdma_channels = 4,8686+ .dai_driver = &ipq806x_lpass_cpu_dai_driver,8787+ .num_dai = 1,8888+ .alloc_dma_channel = ipq806x_lpass_alloc_dma_channel,8989+ .free_dma_channel = ipq806x_lpass_free_dma_channel,9090+};9191+9292+static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {9393+ { .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },9494+ {}9595+};9696+MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);9797+9898+static struct platform_driver ipq806x_lpass_cpu_platform_driver = {9999+ .driver = {100100+ .name = "lpass-cpu",101101+ .of_match_table = of_match_ptr(ipq806x_lpass_cpu_device_id),102102+ },103103+ .probe = asoc_qcom_lpass_cpu_platform_probe,104104+ .remove = asoc_qcom_lpass_cpu_platform_remove,105105+};106106+module_platform_driver(ipq806x_lpass_cpu_platform_driver);107107+108108+MODULE_DESCRIPTION("QTi LPASS CPU Driver");109109+MODULE_LICENSE("GPL v2");
···1313 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS1414 */15151616-#include <linux/compiler.h>1717-#include <linux/device.h>1816#include <linux/dma-mapping.h>1919-#include <linux/err.h>2017#include <linux/export.h>2118#include <linux/kernel.h>2219#include <linux/module.h>2323-#include <linux/io.h>2420#include <linux/platform_device.h>2525-#include <sound/memalloc.h>2626-#include <sound/pcm.h>2721#include <sound/pcm_params.h>2822#include <linux/regmap.h>2923#include <sound/soc.h>3030-#include "lpass-lpaif-ipq806x.h"2424+#include "lpass-lpaif-reg.h"3125#include "lpass.h"2626+2727+struct lpass_pcm_data {2828+ int rdma_ch;2929+ int i2s_port;3030+};32313332#define LPASS_PLATFORM_BUFFER_SIZE (16 * 1024)3433#define LPASS_PLATFORM_PERIODS 2···8384 struct snd_pcm_hw_params *params)8485{8586 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;8787+ struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);8688 struct lpass_data *drvdata =8789 snd_soc_platform_get_drvdata(soc_runtime->platform);9090+ struct lpass_variant *v = drvdata->variant;8891 snd_pcm_format_t format = params_format(params);8992 unsigned int channels = params_channels(params);9093 unsigned int regval;9194 int bitwidth;9292- int ret;9595+ int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;93969497 bitwidth = snd_pcm_format_width(format);9598 if (bitwidth < 0) {···101100 }102101103102 regval = LPAIF_RDMACTL_BURSTEN_INCR4 |104104- LPAIF_RDMACTL_AUDINTF_MI2S |103103+ LPAIF_RDMACTL_AUDINTF(rdma_port) |105104 LPAIF_RDMACTL_FIFOWM_8;106105107106 switch (bitwidth) {···157156 }158157159158 ret = regmap_write(drvdata->lpaif_map,160160- LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);159159+ LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);161160 if (ret) {162161 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",163162 __func__, ret);···170169static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)171170{172171 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;172172+ struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);173173 struct lpass_data *drvdata =174174 snd_soc_platform_get_drvdata(soc_runtime->platform);175175+ struct lpass_variant *v = drvdata->variant;175176 int ret;176177177178 ret = regmap_write(drvdata->lpaif_map,178178- LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);179179+ LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);179180 if (ret)180181 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",181182 __func__, ret);···189186{190187 struct snd_pcm_runtime *runtime = substream->runtime;191188 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;189189+ struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);192190 struct lpass_data *drvdata =193191 snd_soc_platform_get_drvdata(soc_runtime->platform);194194- int ret;192192+ struct lpass_variant *v = drvdata->variant;193193+ int ret, ch = pcm_data->rdma_ch;195194196195 ret = regmap_write(drvdata->lpaif_map,197197- LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),196196+ LPAIF_RDMABASE_REG(v, ch),198197 runtime->dma_addr);199198 if (ret) {200199 dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",···205200 }206201207202 ret = regmap_write(drvdata->lpaif_map,208208- LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),203203+ LPAIF_RDMABUFF_REG(v, ch),209204 (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);210205 if (ret) {211206 dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",···214209 }215210216211 ret = regmap_write(drvdata->lpaif_map,217217- LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),212212+ LPAIF_RDMAPER_REG(v, ch),218213 (snd_pcm_lib_period_bytes(substream) >> 2) - 1);219214 if (ret) {220215 dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",···223218 }224219225220 ret = regmap_update_bits(drvdata->lpaif_map,226226- LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),221221+ LPAIF_RDMACTL_REG(v, ch),227222 LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);228223 if (ret) {229224 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",···238233 int cmd)239234{240235 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;236236+ struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);241237 struct lpass_data *drvdata =242238 snd_soc_platform_get_drvdata(soc_runtime->platform);243243- int ret;239239+ struct lpass_variant *v = drvdata->variant;240240+ int ret, ch = pcm_data->rdma_ch;244241245242 switch (cmd) {246243 case SNDRV_PCM_TRIGGER_START:···250243 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:251244 /* clear status before enabling interrupts */252245 ret = regmap_write(drvdata->lpaif_map,253253- LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),254254- LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));246246+ LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),247247+ LPAIF_IRQ_ALL(ch));255248 if (ret) {256249 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",257250 __func__, ret);···259252 }260253261254 ret = regmap_update_bits(drvdata->lpaif_map,262262- LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),263263- LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),264264- LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));255255+ LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),256256+ LPAIF_IRQ_ALL(ch),257257+ LPAIF_IRQ_ALL(ch));265258 if (ret) {266259 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",267260 __func__, ret);···269262 }270263271264 ret = regmap_update_bits(drvdata->lpaif_map,272272- LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),265265+ LPAIF_RDMACTL_REG(v, ch),273266 LPAIF_RDMACTL_ENABLE_MASK,274267 LPAIF_RDMACTL_ENABLE_ON);275268 if (ret) {···282275 case SNDRV_PCM_TRIGGER_SUSPEND:283276 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:284277 ret = regmap_update_bits(drvdata->lpaif_map,285285- LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),278278+ LPAIF_RDMACTL_REG(v, ch),286279 LPAIF_RDMACTL_ENABLE_MASK,287280 LPAIF_RDMACTL_ENABLE_OFF);288281 if (ret) {···292285 }293286294287 ret = regmap_update_bits(drvdata->lpaif_map,295295- LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),296296- LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);288288+ LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),289289+ LPAIF_IRQ_ALL(ch), 0);297290 if (ret) {298291 dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",299292 __func__, ret);···309302 struct snd_pcm_substream *substream)310303{311304 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;305305+ struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);312306 struct lpass_data *drvdata =313307 snd_soc_platform_get_drvdata(soc_runtime->platform);308308+ struct lpass_variant *v = drvdata->variant;314309 unsigned int base_addr, curr_addr;315315- int ret;310310+ int ret, ch = pcm_data->rdma_ch;316311317312 ret = regmap_read(drvdata->lpaif_map,318318- LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr);313313+ LPAIF_RDMABASE_REG(v, ch), &base_addr);319314 if (ret) {320315 dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",321316 __func__, ret);···325316 }326317327318 ret = regmap_read(drvdata->lpaif_map,328328- LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr);319319+ LPAIF_RDMACURR_REG(v, ch), &curr_addr);329320 if (ret) {330321 dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",331322 __func__, ret);···356347 .mmap = lpass_platform_pcmops_mmap,357348};358349359359-static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)350350+static irqreturn_t lpass_dma_interrupt_handler(351351+ struct snd_pcm_substream *substream,352352+ struct lpass_data *drvdata,353353+ int chan, u32 interrupts)360354{361361- struct snd_pcm_substream *substream = data;362355 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;363363- struct lpass_data *drvdata =364364- snd_soc_platform_get_drvdata(soc_runtime->platform);365365- unsigned int interrupts;356356+ struct lpass_variant *v = drvdata->variant;366357 irqreturn_t ret = IRQ_NONE;367358 int rv;368359369369- rv = regmap_read(drvdata->lpaif_map,370370- LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);371371- if (rv) {372372- dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",373373- __func__, rv);374374- return IRQ_NONE;375375- }376376- interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);377377-378378- if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {360360+ if (interrupts & LPAIF_IRQ_PER(chan)) {379361 rv = regmap_write(drvdata->lpaif_map,380380- LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),381381- LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));362362+ LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),363363+ LPAIF_IRQ_PER(chan));382364 if (rv) {383365 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",384366 __func__, rv);···379379 ret = IRQ_HANDLED;380380 }381381382382- if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {382382+ if (interrupts & LPAIF_IRQ_XRUN(chan)) {383383 rv = regmap_write(drvdata->lpaif_map,384384- LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),385385- LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));384384+ LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),385385+ LPAIF_IRQ_XRUN(chan));386386 if (rv) {387387 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",388388 __func__, rv);···393393 ret = IRQ_HANDLED;394394 }395395396396- if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {396396+ if (interrupts & LPAIF_IRQ_ERR(chan)) {397397 rv = regmap_write(drvdata->lpaif_map,398398- LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),399399- LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));398398+ LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),399399+ LPAIF_IRQ_ERR(chan));400400 if (rv) {401401 dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",402402 __func__, rv);···408408 }409409410410 return ret;411411+}412412+413413+static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)414414+{415415+ struct lpass_data *drvdata = data;416416+ struct lpass_variant *v = drvdata->variant;417417+ unsigned int irqs;418418+ int rv, chan;419419+420420+ rv = regmap_read(drvdata->lpaif_map,421421+ LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);422422+ if (rv) {423423+ pr_err("%s() error reading from irqstat reg: %d\n",424424+ __func__, rv);425425+ return IRQ_NONE;426426+ }427427+428428+ /* Handle per channel interrupts */429429+ for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {430430+ if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {431431+ rv = lpass_dma_interrupt_handler(432432+ drvdata->substream[chan],433433+ drvdata, chan, irqs);434434+ if (rv != IRQ_HANDLED)435435+ return rv;436436+ }437437+ }438438+439439+ return IRQ_HANDLED;411440}412441413442static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,···477448 struct snd_pcm *pcm = soc_runtime->pcm;478449 struct snd_pcm_substream *substream =479450 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;451451+ struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;480452 struct lpass_data *drvdata =481453 snd_soc_platform_get_drvdata(soc_runtime->platform);454454+ struct lpass_variant *v = drvdata->variant;482455 int ret;456456+ struct lpass_pcm_data *data;457457+458458+ data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);459459+ if (!data)460460+ return -ENOMEM;461461+462462+ if (v->alloc_dma_channel)463463+ data->rdma_ch = v->alloc_dma_channel(drvdata);464464+465465+ if (IS_ERR_VALUE(data->rdma_ch))466466+ return data->rdma_ch;467467+468468+ drvdata->substream[data->rdma_ch] = substream;469469+ data->i2s_port = cpu_dai->driver->id;470470+471471+ snd_soc_pcm_set_drvdata(soc_runtime, data);483472484473 soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);485474 soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;···506459 if (ret)507460 return ret;508461509509- ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,510510- lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,511511- "lpass-irq-lpaif", substream);512512- if (ret) {513513- dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",514514- __func__, ret);515515- goto err_buf;516516- }517517-518518- /* ensure audio hardware is disabled */519462 ret = regmap_write(drvdata->lpaif_map,520520- LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);521521- if (ret) {522522- dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",523523- __func__, ret);524524- return ret;525525- }526526- ret = regmap_write(drvdata->lpaif_map,527527- LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);463463+ LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);528464 if (ret) {529465 dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",530466 __func__, ret);531531- return ret;467467+ goto err_buf;532468 }533469534470 return 0;···526496 struct snd_pcm_substream *substream =527497 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;528498 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;499499+ struct lpass_data *drvdata =500500+ snd_soc_platform_get_drvdata(soc_runtime->platform);501501+ struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);502502+ struct lpass_variant *v = drvdata->variant;503503+504504+ drvdata->substream[data->rdma_ch] = NULL;505505+506506+ if (v->free_dma_channel)507507+ v->free_dma_channel(drvdata, data->rdma_ch);529508530509 lpass_platform_free_buffer(substream, soc_runtime);531510}···548509int asoc_qcom_lpass_platform_register(struct platform_device *pdev)549510{550511 struct lpass_data *drvdata = platform_get_drvdata(pdev);512512+ struct lpass_variant *v = drvdata->variant;513513+ int ret;551514552515 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");553516 if (drvdata->lpaif_irq < 0) {···557516 __func__, drvdata->lpaif_irq);558517 return -ENODEV;559518 }519519+520520+ /* ensure audio hardware is disabled */521521+ ret = regmap_write(drvdata->lpaif_map,522522+ LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);523523+ if (ret) {524524+ dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",525525+ __func__, ret);526526+ return ret;527527+ }528528+529529+ ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,530530+ lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,531531+ "lpass-irq-lpaif", drvdata);532532+ if (ret) {533533+ dev_err(&pdev->dev, "%s() irq request failed: %d\n",534534+ __func__, ret);535535+ return ret;536536+ }537537+560538561539 return devm_snd_soc_register_platform(&pdev->dev,562540 &lpass_platform_driver);
+49-2
sound/soc/qcom/lpass.h
···2222#include <linux/regmap.h>23232424#define LPASS_AHBIX_CLOCK_FREQUENCY 1310720002525+#define LPASS_MAX_MI2S_PORTS (8)2626+#define LPASS_MAX_DMA_CHANNELS (8)25272628/* Both the CPU DAI and platform drivers will access this data */2729struct lpass_data {···3230 struct clk *ahbix_clk;33313432 /* MI2S system clock */3535- struct clk *mi2s_osr_clk;3333+ struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];36343735 /* MI2S bit clock (derived from system clock by a divider */3838- struct clk *mi2s_bit_clk;3636+ struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];39374038 /* low-power audio interface (LPAIF) registers */4139 void __iomem *lpaif;···45434644 /* interrupts from the low-power audio interface (LPAIF) */4745 int lpaif_irq;4646+4747+ /* SOC specific variations in the LPASS IP integration */4848+ struct lpass_variant *variant;4949+5050+ /* bit map to keep track of static channel allocations */5151+ unsigned long rdma_ch_bit_map;5252+5353+ /* used it for handling interrupt per dma channel */5454+ struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];5555+5656+ /* 8016 specific */5757+ struct clk *pcnoc_mport_clk;5858+ struct clk *pcnoc_sway_clk;5959+};6060+6161+/* Vairant data per each SOC */6262+struct lpass_variant {6363+ u32 i2sctrl_reg_base;6464+ u32 i2sctrl_reg_stride;6565+ u32 i2s_ports;6666+ u32 irq_reg_base;6767+ u32 irq_reg_stride;6868+ u32 irq_ports;6969+ u32 rdma_reg_base;7070+ u32 rdma_reg_stride;7171+ u32 rdma_channels;7272+7373+ /**7474+ * on SOCs like APQ8016 the channel control bits start7575+ * at different offset to ipq806x7676+ **/7777+ u32 rdmactl_audif_start;7878+ /* SOC specific intialization like clocks */7979+ int (*init)(struct platform_device *pdev);8080+ int (*exit)(struct platform_device *pdev);8181+ int (*alloc_dma_channel)(struct lpass_data *data);8282+ int (*free_dma_channel)(struct lpass_data *data, int ch);8383+8484+ /* SOC specific dais */8585+ struct snd_soc_dai_driver *dai_driver;8686+ int num_dai;4887};49885089/* register the platform driver from the CPU DAI driver */5190int asoc_qcom_lpass_platform_register(struct platform_device *);9191+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);9292+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);9393+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);9494+extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;52955396#endif /* __LPASS_H__ */