1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
- *
- * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
- */
- #include <linux/clk.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_device.h>
- #include <linux/platform_device.h>
- #include <sound/pcm.h>
- #include <sound/pcm_params.h>
- #include <linux/regmap.h>
- #include <sound/soc.h>
- #include <sound/soc-dai.h>
- #include "lpass-lpaif-reg.h"
- #include "lpass.h"
- #define LPASS_CPU_MAX_MI2S_LINES 4
- #define LPASS_CPU_I2S_SD0_MASK BIT(0)
- #define LPASS_CPU_I2S_SD1_MASK BIT(1)
- #define LPASS_CPU_I2S_SD2_MASK BIT(2)
- #define LPASS_CPU_I2S_SD3_MASK BIT(3)
- #define LPASS_CPU_I2S_SD0_1_MASK GENMASK(1, 0)
- #define LPASS_CPU_I2S_SD2_3_MASK GENMASK(3, 2)
- #define LPASS_CPU_I2S_SD0_1_2_MASK GENMASK(2, 0)
- #define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 0)
- #define LPASS_REG_READ 1
- #define LPASS_REG_WRITE 0
- /*
- * Channel maps for Quad channel playbacks on MI2S Secondary
- */
- static struct snd_pcm_chmap_elem lpass_quad_chmaps[] = {
- { .channels = 4,
- .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_RL,
- SNDRV_CHMAP_FR, SNDRV_CHMAP_RR } },
- { }
- };
- static int lpass_cpu_init_i2sctl_bitfields(struct device *dev,
- struct lpaif_i2sctl *i2sctl, struct regmap *map)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback);
- i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken);
- i2sctl->spkmode = devm_regmap_field_alloc(dev, map, v->spkmode);
- i2sctl->spkmono = devm_regmap_field_alloc(dev, map, v->spkmono);
- i2sctl->micen = devm_regmap_field_alloc(dev, map, v->micen);
- i2sctl->micmode = devm_regmap_field_alloc(dev, map, v->micmode);
- i2sctl->micmono = devm_regmap_field_alloc(dev, map, v->micmono);
- i2sctl->wssrc = devm_regmap_field_alloc(dev, map, v->wssrc);
- i2sctl->bitwidth = devm_regmap_field_alloc(dev, map, v->bitwidth);
- if (IS_ERR(i2sctl->loopback) || IS_ERR(i2sctl->spken) ||
- IS_ERR(i2sctl->spkmode) || IS_ERR(i2sctl->spkmono) ||
- IS_ERR(i2sctl->micen) || IS_ERR(i2sctl->micmode) ||
- IS_ERR(i2sctl->micmono) || IS_ERR(i2sctl->wssrc) ||
- IS_ERR(i2sctl->bitwidth))
- return -EINVAL;
- return 0;
- }
- static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
- unsigned int freq, int dir)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- int ret;
- ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
- if (ret)
- dev_err(dai->dev, "error setting mi2s osrclk to %u: %d\n",
- freq, ret);
- return ret;
- }
- static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- int ret;
- ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->driver->id]);
- if (ret) {
- dev_err(dai->dev, "error in enabling mi2s osr clk: %d\n", ret);
- return ret;
- }
- ret = clk_prepare(drvdata->mi2s_bit_clk[dai->driver->id]);
- if (ret) {
- dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
- clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
- return ret;
- }
- return 0;
- }
- static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
- unsigned int id = dai->driver->id;
- clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
- /*
- * Ensure LRCLK is disabled even in device node validation.
- * Will not impact if disabled in lpass_cpu_daiops_trigger()
- * suspend.
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
- else
- regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
- /*
- * BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
- * lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
- * lpass_cpu_daiops_prepare.
- */
- if (drvdata->mi2s_was_prepared[dai->driver->id]) {
- drvdata->mi2s_was_prepared[dai->driver->id] = false;
- clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
- }
- clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
- }
- static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
- unsigned int id = dai->driver->id;
- snd_pcm_format_t format = params_format(params);
- unsigned int channels = params_channels(params);
- unsigned int rate = params_rate(params);
- unsigned int mode;
- unsigned int regval;
- int bitwidth, ret;
- bitwidth = snd_pcm_format_width(format);
- if (bitwidth < 0) {
- dev_err(dai->dev, "invalid bit width given: %d\n", bitwidth);
- return bitwidth;
- }
- ret = regmap_fields_write(i2sctl->loopback, id,
- LPAIF_I2SCTL_LOOPBACK_DISABLE);
- if (ret) {
- dev_err(dai->dev, "error updating loopback field: %d\n", ret);
- return ret;
- }
- ret = regmap_fields_write(i2sctl->wssrc, id,
- LPAIF_I2SCTL_WSSRC_INTERNAL);
- if (ret) {
- dev_err(dai->dev, "error updating wssrc field: %d\n", ret);
- return ret;
- }
- switch (bitwidth) {
- case 16:
- regval = LPAIF_I2SCTL_BITWIDTH_16;
- break;
- case 24:
- regval = LPAIF_I2SCTL_BITWIDTH_24;
- break;
- case 32:
- regval = LPAIF_I2SCTL_BITWIDTH_32;
- break;
- default:
- dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
- return -EINVAL;
- }
- ret = regmap_fields_write(i2sctl->bitwidth, id, regval);
- if (ret) {
- dev_err(dai->dev, "error updating bitwidth field: %d\n", ret);
- return ret;
- }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- mode = drvdata->mi2s_playback_sd_mode[id];
- else
- mode = drvdata->mi2s_capture_sd_mode[id];
- if (!mode) {
- dev_err(dai->dev, "no line is assigned\n");
- return -EINVAL;
- }
- switch (channels) {
- case 1:
- case 2:
- switch (mode) {
- case LPAIF_I2SCTL_MODE_QUAD01:
- case LPAIF_I2SCTL_MODE_6CH:
- case LPAIF_I2SCTL_MODE_8CH:
- mode = LPAIF_I2SCTL_MODE_SD0;
- break;
- case LPAIF_I2SCTL_MODE_QUAD23:
- mode = LPAIF_I2SCTL_MODE_SD2;
- break;
- }
- break;
- case 4:
- if (mode < LPAIF_I2SCTL_MODE_QUAD01) {
- dev_err(dai->dev, "cannot configure 4 channels with mode %d\n",
- mode);
- return -EINVAL;
- }
- switch (mode) {
- case LPAIF_I2SCTL_MODE_6CH:
- case LPAIF_I2SCTL_MODE_8CH:
- mode = LPAIF_I2SCTL_MODE_QUAD01;
- break;
- }
- break;
- case 6:
- if (mode < LPAIF_I2SCTL_MODE_6CH) {
- dev_err(dai->dev, "cannot configure 6 channels with mode %d\n",
- mode);
- return -EINVAL;
- }
- switch (mode) {
- case LPAIF_I2SCTL_MODE_8CH:
- mode = LPAIF_I2SCTL_MODE_6CH;
- break;
- }
- break;
- case 8:
- if (mode < LPAIF_I2SCTL_MODE_8CH) {
- dev_err(dai->dev, "cannot configure 8 channels with mode %d\n",
- mode);
- return -EINVAL;
- }
- break;
- default:
- dev_err(dai->dev, "invalid channels given: %u\n", channels);
- return -EINVAL;
- }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = regmap_fields_write(i2sctl->spkmode, id,
- LPAIF_I2SCTL_SPKMODE(mode));
- if (ret) {
- dev_err(dai->dev, "error writing to i2sctl spkr mode: %d\n",
- ret);
- return ret;
- }
- if (channels >= 2)
- ret = regmap_fields_write(i2sctl->spkmono, id,
- LPAIF_I2SCTL_SPKMONO_STEREO);
- else
- ret = regmap_fields_write(i2sctl->spkmono, id,
- LPAIF_I2SCTL_SPKMONO_MONO);
- } else {
- ret = regmap_fields_write(i2sctl->micmode, id,
- LPAIF_I2SCTL_MICMODE(mode));
- if (ret) {
- dev_err(dai->dev, "error writing to i2sctl mic mode: %d\n",
- ret);
- return ret;
- }
- if (channels >= 2)
- ret = regmap_fields_write(i2sctl->micmono, id,
- LPAIF_I2SCTL_MICMONO_STEREO);
- else
- ret = regmap_fields_write(i2sctl->micmono, id,
- LPAIF_I2SCTL_MICMONO_MONO);
- }
- if (ret) {
- dev_err(dai->dev, "error writing to i2sctl channels mode: %d\n",
- ret);
- return ret;
- }
- ret = clk_set_rate(drvdata->mi2s_bit_clk[id],
- rate * bitwidth * 2);
- if (ret) {
- dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
- rate * bitwidth * 2, ret);
- return ret;
- }
- return 0;
- }
- static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
- unsigned int id = dai->driver->id;
- int ret = -EINVAL;
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- /*
- * Ensure lpass BCLK/LRCLK is enabled during
- * device resume as lpass_cpu_daiops_prepare() is not called
- * after the device resumes. We don't check mi2s_was_prepared before
- * enable/disable BCLK in trigger events because:
- * 1. These trigger events are paired, so the BCLK
- * enable_count is balanced.
- * 2. the BCLK can be shared (ex: headset and headset mic),
- * we need to increase the enable_count so that we don't
- * turn off the shared BCLK while other devices are using
- * it.
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = regmap_fields_write(i2sctl->spken, id,
- LPAIF_I2SCTL_SPKEN_ENABLE);
- } else {
- ret = regmap_fields_write(i2sctl->micen, id,
- LPAIF_I2SCTL_MICEN_ENABLE);
- }
- if (ret)
- dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
- ret);
- ret = clk_enable(drvdata->mi2s_bit_clk[id]);
- if (ret) {
- dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
- clk_disable(drvdata->mi2s_osr_clk[id]);
- return ret;
- }
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- /*
- * To ensure lpass BCLK/LRCLK is disabled during
- * device suspend.
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = regmap_fields_write(i2sctl->spken, id,
- LPAIF_I2SCTL_SPKEN_DISABLE);
- } else {
- ret = regmap_fields_write(i2sctl->micen, id,
- LPAIF_I2SCTL_MICEN_DISABLE);
- }
- if (ret)
- dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
- ret);
- clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
- break;
- }
- return ret;
- }
- static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
- unsigned int id = dai->driver->id;
- int ret;
- /*
- * Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
- * data flow starts. This allows other codec to have some delay before
- * the data flow.
- * (ex: to drop start up pop noise before capture starts).
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
- else
- ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
- if (ret) {
- dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
- return ret;
- }
- /*
- * Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
- * be called multiple times. It's paired with the clk_disable in
- * lpass_cpu_daiops_shutdown.
- */
- if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
- ret = clk_enable(drvdata->mi2s_bit_clk[id]);
- if (ret) {
- dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
- return ret;
- }
- drvdata->mi2s_was_prepared[dai->driver->id] = true;
- }
- return 0;
- }
- const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
- .set_sysclk = lpass_cpu_daiops_set_sysclk,
- .startup = lpass_cpu_daiops_startup,
- .shutdown = lpass_cpu_daiops_shutdown,
- .hw_params = lpass_cpu_daiops_hw_params,
- .trigger = lpass_cpu_daiops_trigger,
- .prepare = lpass_cpu_daiops_prepare,
- };
- EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
- int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai)
- {
- int ret;
- struct snd_soc_dai_driver *drv = dai->driver;
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- if (drvdata->mi2s_playback_sd_mode[dai->id] == LPAIF_I2SCTL_MODE_QUAD01) {
- ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
- lpass_quad_chmaps, drv->playback.channels_max, 0,
- NULL);
- if (ret < 0)
- return ret;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new);
- int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
- {
- struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
- int ret;
- /* ensure audio hardware is disabled */
- ret = regmap_write(drvdata->lpaif_map,
- LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
- if (ret)
- dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
- return ret;
- }
- EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
- static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
- const struct of_phandle_args *args,
- const char **dai_name)
- {
- struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
- struct lpass_variant *variant = drvdata->variant;
- int id = args->args[0];
- int ret = -EINVAL;
- int i;
- for (i = 0; i < variant->num_dai; i++) {
- if (variant->dai_driver[i].id == id) {
- *dai_name = variant->dai_driver[i].name;
- ret = 0;
- break;
- }
- }
- return ret;
- }
- static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
- .name = "lpass-cpu",
- .of_xlate_dai_name = asoc_qcom_of_xlate_dai_name,
- .legacy_dai_naming = 1,
- };
- static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->i2s_ports; ++i)
- if (reg == LPAIF_I2SCTL_REG(v, i))
- return true;
- for (i = 0; i < v->irq_ports; ++i) {
- if (reg == LPAIF_IRQEN_REG(v, i))
- return true;
- if (reg == LPAIF_IRQCLEAR_REG(v, i))
- return true;
- }
- for (i = 0; i < v->rdma_channels; ++i) {
- if (reg == LPAIF_RDMACTL_REG(v, i))
- return true;
- if (reg == LPAIF_RDMABASE_REG(v, i))
- return true;
- if (reg == LPAIF_RDMABUFF_REG(v, i))
- return true;
- if (reg == LPAIF_RDMAPER_REG(v, i))
- return true;
- }
- for (i = 0; i < v->wrdma_channels; ++i) {
- if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
- return true;
- }
- return false;
- }
- static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->i2s_ports; ++i)
- if (reg == LPAIF_I2SCTL_REG(v, i))
- return true;
- for (i = 0; i < v->irq_ports; ++i) {
- if (reg == LPAIF_IRQCLEAR_REG(v, i))
- return true;
- if (reg == LPAIF_IRQEN_REG(v, i))
- return true;
- if (reg == LPAIF_IRQSTAT_REG(v, i))
- return true;
- }
- for (i = 0; i < v->rdma_channels; ++i) {
- if (reg == LPAIF_RDMACTL_REG(v, i))
- return true;
- if (reg == LPAIF_RDMABASE_REG(v, i))
- return true;
- if (reg == LPAIF_RDMABUFF_REG(v, i))
- return true;
- if (reg == LPAIF_RDMACURR_REG(v, i))
- return true;
- if (reg == LPAIF_RDMAPER_REG(v, i))
- return true;
- }
- for (i = 0; i < v->wrdma_channels; ++i) {
- if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
- return true;
- if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
- return true;
- }
- return false;
- }
- static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->irq_ports; ++i) {
- if (reg == LPAIF_IRQCLEAR_REG(v, i))
- return true;
- if (reg == LPAIF_IRQSTAT_REG(v, i))
- return true;
- }
- for (i = 0; i < v->rdma_channels; ++i)
- if (reg == LPAIF_RDMACURR_REG(v, i))
- return true;
- for (i = 0; i < v->wrdma_channels; ++i)
- if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
- return true;
- return false;
- }
- static struct regmap_config lpass_cpu_regmap_config = {
- .name = "lpass_cpu",
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .writeable_reg = lpass_cpu_regmap_writeable,
- .readable_reg = lpass_cpu_regmap_readable,
- .volatile_reg = lpass_cpu_regmap_volatile,
- .cache_type = REGCACHE_FLAT,
- };
- static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- unsigned int i;
- struct lpass_hdmi_tx_ctl *tx_ctl;
- struct regmap_field *legacy_en;
- struct lpass_vbit_ctrl *vbit_ctl;
- struct regmap_field *tx_parity;
- struct lpass_dp_metadata_ctl *meta_ctl;
- struct lpass_sstream_ctl *sstream_ctl;
- struct regmap_field *ch_msb;
- struct regmap_field *ch_lsb;
- struct lpass_hdmitx_dmactl *tx_dmactl;
- int rval;
- tx_ctl = devm_kzalloc(dev, sizeof(*tx_ctl), GFP_KERNEL);
- if (!tx_ctl)
- return -ENOMEM;
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->soft_reset, tx_ctl->soft_reset);
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->force_reset, tx_ctl->force_reset);
- drvdata->tx_ctl = tx_ctl;
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->legacy_en, legacy_en);
- drvdata->hdmitx_legacy_en = legacy_en;
- vbit_ctl = devm_kzalloc(dev, sizeof(*vbit_ctl), GFP_KERNEL);
- if (!vbit_ctl)
- return -ENOMEM;
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->replace_vbit, vbit_ctl->replace_vbit);
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->vbit_stream, vbit_ctl->vbit_stream);
- drvdata->vbit_ctl = vbit_ctl;
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->calc_en, tx_parity);
- drvdata->hdmitx_parity_calc_en = tx_parity;
- meta_ctl = devm_kzalloc(dev, sizeof(*meta_ctl), GFP_KERNEL);
- if (!meta_ctl)
- return -ENOMEM;
- rval = devm_regmap_field_bulk_alloc(dev, map, &meta_ctl->mute, &v->mute, 7);
- if (rval)
- return rval;
- drvdata->meta_ctl = meta_ctl;
- sstream_ctl = devm_kzalloc(dev, sizeof(*sstream_ctl), GFP_KERNEL);
- if (!sstream_ctl)
- return -ENOMEM;
- rval = devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, &v->sstream_en, 9);
- if (rval)
- return rval;
- drvdata->sstream_ctl = sstream_ctl;
- for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->msb_bits, ch_msb);
- drvdata->hdmitx_ch_msb[i] = ch_msb;
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->lsb_bits, ch_lsb);
- drvdata->hdmitx_ch_lsb[i] = ch_lsb;
- tx_dmactl = devm_kzalloc(dev, sizeof(*tx_dmactl), GFP_KERNEL);
- if (!tx_dmactl)
- return -ENOMEM;
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_chs, tx_dmactl->use_hw_chs);
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_usr, tx_dmactl->use_hw_usr);
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_chs_sel, tx_dmactl->hw_chs_sel);
- QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_usr_sel, tx_dmactl->hw_usr_sel);
- drvdata->hdmi_tx_dmactl[i] = tx_dmactl;
- }
- return 0;
- }
- static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_DP_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
- return true;
- if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
- return true;
- if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
- return true;
- for (i = 0; i < v->hdmi_rdma_channels; i++) {
- if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
- return true;
- }
- for (i = 0; i < v->hdmi_rdma_channels; ++i) {
- if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
- return true;
- }
- return false;
- }
- static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
- return true;
- for (i = 0; i < v->hdmi_rdma_channels; i++) {
- if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
- return true;
- }
- if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_DP_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
- return true;
- if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
- return true;
- if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
- return true;
- for (i = 0; i < v->hdmi_rdma_channels; ++i) {
- if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
- return true;
- if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
- return true;
- }
- return false;
- }
- static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
- return true;
- if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
- return true;
- if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
- return true;
- for (i = 0; i < v->hdmi_rdma_channels; ++i) {
- if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
- return true;
- if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
- return true;
- }
- return false;
- }
- static struct regmap_config lpass_hdmi_regmap_config = {
- .name = "lpass_hdmi",
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .writeable_reg = lpass_hdmi_regmap_writeable,
- .readable_reg = lpass_hdmi_regmap_readable,
- .volatile_reg = lpass_hdmi_regmap_volatile,
- .cache_type = REGCACHE_FLAT,
- };
- static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->rxtx_irq_ports; ++i) {
- if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
- return true;
- if (reg == LPAIF_RXTX_IRQEN_REG(v, i))
- return true;
- if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
- return true;
- }
- for (i = 0; i < v->rxtx_rdma_channels; ++i) {
- if (reg == LPAIF_CDC_RXTX_RDMACTL_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- if (reg == LPAIF_CDC_RXTX_RDMABASE_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- if (reg == LPAIF_CDC_RXTX_RDMABUFF_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- if (rw == LPASS_REG_READ) {
- if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- }
- if (reg == LPAIF_CDC_RXTX_RDMAPER_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- if (reg == LPAIF_CDC_RXTX_RDMA_INTF_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- }
- for (i = 0; i < v->rxtx_wrdma_channels; ++i) {
- if (reg == LPAIF_CDC_RXTX_WRDMACTL_REG(v, i + v->rxtx_wrdma_channel_start,
- LPASS_CDC_DMA_TX3))
- return true;
- if (reg == LPAIF_CDC_RXTX_WRDMABASE_REG(v, i + v->rxtx_wrdma_channel_start,
- LPASS_CDC_DMA_TX3))
- return true;
- if (reg == LPAIF_CDC_RXTX_WRDMABUFF_REG(v, i + v->rxtx_wrdma_channel_start,
- LPASS_CDC_DMA_TX3))
- return true;
- if (rw == LPASS_REG_READ) {
- if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- }
- if (reg == LPAIF_CDC_RXTX_WRDMAPER_REG(v, i + v->rxtx_wrdma_channel_start,
- LPASS_CDC_DMA_TX3))
- return true;
- if (reg == LPAIF_CDC_RXTX_WRDMA_INTF_REG(v, i + v->rxtx_wrdma_channel_start,
- LPASS_CDC_DMA_TX3))
- return true;
- }
- return false;
- }
- static bool lpass_rxtx_regmap_writeable(struct device *dev, unsigned int reg)
- {
- return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
- }
- static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
- {
- return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
- }
- static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->rxtx_irq_ports; ++i) {
- if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
- return true;
- if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
- return true;
- }
- for (i = 0; i < v->rxtx_rdma_channels; ++i)
- if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
- return true;
- for (i = 0; i < v->rxtx_wrdma_channels; ++i)
- if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i + v->rxtx_wrdma_channel_start,
- LPASS_CDC_DMA_TX3))
- return true;
- return false;
- }
- static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->va_irq_ports; ++i) {
- if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
- return true;
- if (reg == LPAIF_VA_IRQEN_REG(v, i))
- return true;
- if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
- return true;
- }
- for (i = 0; i < v->va_wrdma_channels; ++i) {
- if (reg == LPAIF_CDC_VA_WRDMACTL_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- if (reg == LPAIF_CDC_VA_WRDMABASE_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- if (reg == LPAIF_CDC_VA_WRDMABUFF_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- if (rw == LPASS_REG_READ) {
- if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- }
- if (reg == LPAIF_CDC_VA_WRDMAPER_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- if (reg == LPAIF_CDC_VA_WRDMA_INTF_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- }
- return false;
- }
- static bool lpass_va_regmap_writeable(struct device *dev, unsigned int reg)
- {
- return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
- }
- static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
- {
- return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
- }
- static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
- {
- struct lpass_data *drvdata = dev_get_drvdata(dev);
- struct lpass_variant *v = drvdata->variant;
- int i;
- for (i = 0; i < v->va_irq_ports; ++i) {
- if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
- return true;
- if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
- return true;
- }
- for (i = 0; i < v->va_wrdma_channels; ++i) {
- if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
- LPASS_CDC_DMA_VA_TX0))
- return true;
- }
- return false;
- }
- static struct regmap_config lpass_rxtx_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .writeable_reg = lpass_rxtx_regmap_writeable,
- .readable_reg = lpass_rxtx_regmap_readable,
- .volatile_reg = lpass_rxtx_regmap_volatile,
- .cache_type = REGCACHE_FLAT,
- };
- static struct regmap_config lpass_va_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .writeable_reg = lpass_va_regmap_writeable,
- .readable_reg = lpass_va_regmap_readable,
- .volatile_reg = lpass_va_regmap_volatile,
- .cache_type = REGCACHE_FLAT,
- };
- static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
- struct device_node *node,
- const char *name)
- {
- unsigned int lines[LPASS_CPU_MAX_MI2S_LINES];
- unsigned int sd_line_mask = 0;
- int num_lines, i;
- num_lines = of_property_read_variable_u32_array(node, name, lines, 0,
- LPASS_CPU_MAX_MI2S_LINES);
- if (num_lines < 0)
- return LPAIF_I2SCTL_MODE_NONE;
- for (i = 0; i < num_lines; i++)
- sd_line_mask |= BIT(lines[i]);
- switch (sd_line_mask) {
- case LPASS_CPU_I2S_SD0_MASK:
- return LPAIF_I2SCTL_MODE_SD0;
- case LPASS_CPU_I2S_SD1_MASK:
- return LPAIF_I2SCTL_MODE_SD1;
- case LPASS_CPU_I2S_SD2_MASK:
- return LPAIF_I2SCTL_MODE_SD2;
- case LPASS_CPU_I2S_SD3_MASK:
- return LPAIF_I2SCTL_MODE_SD3;
- case LPASS_CPU_I2S_SD0_1_MASK:
- return LPAIF_I2SCTL_MODE_QUAD01;
- case LPASS_CPU_I2S_SD2_3_MASK:
- return LPAIF_I2SCTL_MODE_QUAD23;
- case LPASS_CPU_I2S_SD0_1_2_MASK:
- return LPAIF_I2SCTL_MODE_6CH;
- case LPASS_CPU_I2S_SD0_1_2_3_MASK:
- return LPAIF_I2SCTL_MODE_8CH;
- default:
- dev_err(dev, "Unsupported SD line mask: %#x\n", sd_line_mask);
- return LPAIF_I2SCTL_MODE_NONE;
- }
- }
- static void of_lpass_cpu_parse_dai_data(struct device *dev,
- struct lpass_data *data)
- {
- struct device_node *node;
- int ret, i, id;
- /* Allow all channels by default for backwards compatibility */
- for (i = 0; i < data->variant->num_dai; i++) {
- id = data->variant->dai_driver[i].id;
- data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
- data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
- }
- for_each_child_of_node(dev->of_node, node) {
- ret = of_property_read_u32(node, "reg", &id);
- if (ret || id < 0) {
- dev_err(dev, "valid dai id not found: %d\n", ret);
- continue;
- }
- if (id == LPASS_DP_RX) {
- data->hdmi_port_enable = 1;
- } else if (is_cdc_dma_port(id)) {
- data->codec_dma_enable = 1;
- } else {
- data->mi2s_playback_sd_mode[id] =
- of_lpass_cpu_parse_sd_lines(dev, node,
- "qcom,playback-sd-lines");
- data->mi2s_capture_sd_mode[id] =
- of_lpass_cpu_parse_sd_lines(dev, node,
- "qcom,capture-sd-lines");
- }
- }
- }
- static int of_lpass_cdc_dma_clks_parse(struct device *dev,
- struct lpass_data *data)
- {
- data->codec_mem0 = devm_clk_get(dev, "audio_cc_codec_mem0");
- if (IS_ERR(data->codec_mem0))
- return PTR_ERR(data->codec_mem0);
- data->codec_mem1 = devm_clk_get(dev, "audio_cc_codec_mem1");
- if (IS_ERR(data->codec_mem1))
- return PTR_ERR(data->codec_mem1);
- data->codec_mem2 = devm_clk_get(dev, "audio_cc_codec_mem2");
- if (IS_ERR(data->codec_mem2))
- return PTR_ERR(data->codec_mem2);
- data->va_mem0 = devm_clk_get(dev, "aon_cc_va_mem0");
- if (IS_ERR(data->va_mem0))
- return PTR_ERR(data->va_mem0);
- return 0;
- }
- int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
- {
- struct lpass_data *drvdata;
- struct device_node *dsp_of_node;
- struct resource *res;
- struct lpass_variant *variant;
- struct device *dev = &pdev->dev;
- const struct of_device_id *match;
- int ret, i, dai_id;
- dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
- if (dsp_of_node) {
- dev_err(dev, "DSP exists and holds audio resources\n");
- of_node_put(dsp_of_node);
- return -EBUSY;
- }
- drvdata = devm_kzalloc(dev, sizeof(struct lpass_data), GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
- platform_set_drvdata(pdev, drvdata);
- match = of_match_device(dev->driver->of_match_table, dev);
- if (!match || !match->data)
- return -EINVAL;
- if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) {
- dev_warn(dev, "%s compatible is deprecated\n",
- match->compatible);
- }
- drvdata->variant = (struct lpass_variant *)match->data;
- variant = drvdata->variant;
- of_lpass_cpu_parse_dai_data(dev, drvdata);
- if (drvdata->codec_dma_enable) {
- drvdata->rxtx_lpaif =
- devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
- if (IS_ERR(drvdata->rxtx_lpaif))
- return PTR_ERR(drvdata->rxtx_lpaif);
- drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
- if (IS_ERR(drvdata->va_lpaif))
- return PTR_ERR(drvdata->va_lpaif);
- lpass_rxtx_regmap_config.max_register = LPAIF_CDC_RXTX_WRDMAPER_REG(variant,
- variant->rxtx_wrdma_channels +
- variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
- drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
- &lpass_rxtx_regmap_config);
- if (IS_ERR(drvdata->rxtx_lpaif_map))
- return PTR_ERR(drvdata->rxtx_lpaif_map);
- lpass_va_regmap_config.max_register = LPAIF_CDC_VA_WRDMAPER_REG(variant,
- variant->va_wrdma_channels +
- variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
- drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
- &lpass_va_regmap_config);
- if (IS_ERR(drvdata->va_lpaif_map))
- return PTR_ERR(drvdata->va_lpaif_map);
- ret = of_lpass_cdc_dma_clks_parse(dev, drvdata);
- if (ret) {
- dev_err(dev, "failed to get cdc dma clocks %d\n", ret);
- return ret;
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
- drvdata->rxtx_cdc_dma_lpm_buf = res->start;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
- drvdata->va_cdc_dma_lpm_buf = res->start;
- }
- drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
- if (IS_ERR(drvdata->lpaif))
- return PTR_ERR(drvdata->lpaif);
- lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
- variant->wrdma_channels +
- variant->wrdma_channel_start);
- drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
- &lpass_cpu_regmap_config);
- if (IS_ERR(drvdata->lpaif_map)) {
- dev_err(dev, "error initializing regmap: %ld\n",
- PTR_ERR(drvdata->lpaif_map));
- return PTR_ERR(drvdata->lpaif_map);
- }
- if (drvdata->hdmi_port_enable) {
- drvdata->hdmiif = devm_platform_ioremap_resource_byname(pdev, "lpass-hdmiif");
- if (IS_ERR(drvdata->hdmiif))
- return PTR_ERR(drvdata->hdmiif);
- lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
- variant->hdmi_rdma_channels - 1);
- drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
- &lpass_hdmi_regmap_config);
- if (IS_ERR(drvdata->hdmiif_map)) {
- dev_err(dev, "error initializing regmap: %ld\n",
- PTR_ERR(drvdata->hdmiif_map));
- return PTR_ERR(drvdata->hdmiif_map);
- }
- }
- if (variant->init) {
- ret = variant->init(pdev);
- if (ret) {
- dev_err(dev, "error initializing variant: %d\n", ret);
- return ret;
- }
- }
- for (i = 0; i < variant->num_dai; i++) {
- dai_id = variant->dai_driver[i].id;
- if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
- continue;
- drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
- variant->dai_osr_clk_names[i]);
- drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(dev,
- variant->dai_bit_clk_names[i]);
- if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
- dev_err(dev,
- "error getting %s: %ld\n",
- variant->dai_bit_clk_names[i],
- PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
- return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
- }
- if (drvdata->mi2s_playback_sd_mode[dai_id] ==
- LPAIF_I2SCTL_MODE_QUAD01) {
- variant->dai_driver[dai_id].playback.channels_min = 4;
- variant->dai_driver[dai_id].playback.channels_max = 4;
- }
- }
- /* Allocation for i2sctl regmap fields */
- drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
- GFP_KERNEL);
- /* Initialize bitfields for dai I2SCTL register */
- ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
- drvdata->lpaif_map);
- if (ret) {
- dev_err(dev, "error init i2sctl field: %d\n", ret);
- return ret;
- }
- if (drvdata->hdmi_port_enable) {
- ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
- if (ret) {
- dev_err(dev, "%s error hdmi init failed\n", __func__);
- return ret;
- }
- }
- ret = devm_snd_soc_register_component(dev,
- &lpass_cpu_comp_driver,
- variant->dai_driver,
- variant->num_dai);
- if (ret) {
- dev_err(dev, "error registering cpu driver: %d\n", ret);
- goto err;
- }
- ret = asoc_qcom_lpass_platform_register(pdev);
- if (ret) {
- dev_err(dev, "error registering platform driver: %d\n", ret);
- goto err;
- }
- err:
- return ret;
- }
- EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
- int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
- {
- struct lpass_data *drvdata = platform_get_drvdata(pdev);
- if (drvdata->variant->exit)
- drvdata->variant->exit(pdev);
- return 0;
- }
- EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
- void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev)
- {
- struct lpass_data *drvdata = platform_get_drvdata(pdev);
- if (drvdata->variant->exit)
- drvdata->variant->exit(pdev);
- }
- EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown);
- MODULE_DESCRIPTION("QTi LPASS CPU Driver");
- MODULE_LICENSE("GPL v2");
|