// 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 <dt-bindings/sound/qcom,lpass.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.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);
const 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);