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); int ret; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_DISABLE); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); break; } return ret; }
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); int ret = -EINVAL; unsigned int val, mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val = LPAIF_I2SCTL_SPKEN_ENABLE; mask = LPAIF_I2SCTL_SPKEN_MASK; } else { val = LPAIF_I2SCTL_MICEN_ENABLE; mask = LPAIF_I2SCTL_MICEN_MASK; } ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val = LPAIF_I2SCTL_SPKEN_DISABLE; mask = LPAIF_I2SCTL_SPKEN_MASK; } else { val = LPAIF_I2SCTL_MICEN_DISABLE; mask = LPAIF_I2SCTL_MICEN_MASK; } ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); break; } return ret; }
static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) { int i; for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i) if (reg == LPAIF_I2SCTL_REG(i)) return true; for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) { if (reg == LPAIF_IRQEN_REG(i)) return true; if (reg == LPAIF_IRQSTAT_REG(i)) return true; } for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) { if (reg == LPAIF_RDMACTL_REG(i)) return true; if (reg == LPAIF_RDMABASE_REG(i)) return true; if (reg == LPAIF_RDMABUFF_REG(i)) return true; if (reg == LPAIF_RDMACURR_REG(i)) return true; if (reg == LPAIF_RDMAPER_REG(i)) 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_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; } return false; }
static int 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(LPAIF_I2S_PORT_MI2S), 0); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); return ret; }
static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; ret = regmap_write(drvdata->lpaif_map, LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); 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); int ret; ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); 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); int ret; unsigned int val, mask; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val = LPAIF_I2SCTL_SPKEN_ENABLE; mask = LPAIF_I2SCTL_SPKEN_MASK; } else { val = LPAIF_I2SCTL_MICEN_ENABLE; mask = LPAIF_I2SCTL_MICEN_MASK; } ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); return ret; }
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); snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); unsigned int regval; int bitwidth, ret; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { dev_err(dai->dev, "%s() invalid bit width given: %d\n", __func__, bitwidth); return bitwidth; } regval = LPAIF_I2SCTL_LOOPBACK_DISABLE | LPAIF_I2SCTL_WSSRC_INTERNAL; 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, "%s() invalid bitwidth given: %d\n", __func__, bitwidth); return -EINVAL; } switch (channels) { case 1: regval |= LPAIF_I2SCTL_SPKMODE_SD0; regval |= LPAIF_I2SCTL_SPKMONO_MONO; break; case 2: regval |= LPAIF_I2SCTL_SPKMODE_SD0; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; case 4: regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; case 6: regval |= LPAIF_I2SCTL_SPKMODE_6CH; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; case 8: regval |= LPAIF_I2SCTL_SPKMODE_8CH; regval |= LPAIF_I2SCTL_SPKMONO_STEREO; break; default: dev_err(dai->dev, "%s() invalid channels given: %u\n", __func__, channels); return -EINVAL; } ret = regmap_write(drvdata->lpaif_map, LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval); if (ret) { dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); return ret; } ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2); if (ret) { dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", __func__, rate * bitwidth * 2, ret); return ret; } return 0; }