Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a391dbe0 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'asoc/topic/atmel', 'asoc/topic/bcm2835' and...

Merge remote-tracking branches 'asoc/topic/atmel', 'asoc/topic/bcm2835' and 'asoc/topic/cs42xx8' into asoc-next
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
		if (ssc->pdev->dev.of_node) {
			if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc")
				== ssc_num) {
				ssc->pdev->id = ssc_num;
				ssc_valid = 1;
				break;
			}
+18 −9
Original line number Diff line number Diff line
@@ -285,7 +285,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
			     struct snd_soc_dai *dai)
{
	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
	struct platform_device *pdev = to_platform_device(dai->dev);
	struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];
	struct atmel_pcm_dma_params *dma_params;
	int dir, dir_mask;
	int ret;
@@ -346,7 +347,8 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
			       struct snd_soc_dai *dai)
{
	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
	struct platform_device *pdev = to_platform_device(dai->dev);
	struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];
	struct atmel_pcm_dma_params *dma_params;
	int dir, dir_mask;

@@ -392,7 +394,8 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
		unsigned int fmt)
{
	struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
	struct platform_device *pdev = to_platform_device(cpu_dai->dev);
	struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];

	ssc_p->daifmt = fmt;
	return 0;
@@ -404,7 +407,8 @@ static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
	int div_id, int div)
{
	struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
	struct platform_device *pdev = to_platform_device(cpu_dai->dev);
	struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];

	switch (div_id) {
	case ATMEL_SSC_CMR_DIV:
@@ -445,7 +449,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params,
	struct snd_soc_dai *dai)
{
	int id = dai->id;
	struct platform_device *pdev = to_platform_device(dai->dev);
	int id = pdev->id;
	struct atmel_ssc_info *ssc_p = &ssc_info[id];
	struct ssc_device *ssc = ssc_p->ssc;
	struct atmel_pcm_dma_params *dma_params;
@@ -772,7 +777,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
			     struct snd_soc_dai *dai)
{
	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
	struct platform_device *pdev = to_platform_device(dai->dev);
	struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];
	struct atmel_pcm_dma_params *dma_params;
	int dir;

@@ -795,7 +801,8 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
			     int cmd, struct snd_soc_dai *dai)
{
	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
	struct platform_device *pdev = to_platform_device(dai->dev);
	struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id];
	struct atmel_pcm_dma_params *dma_params;
	int dir;

@@ -824,11 +831,12 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
{
	struct atmel_ssc_info *ssc_p;
	struct platform_device *pdev = to_platform_device(cpu_dai->dev);

	if (!cpu_dai->active)
		return 0;

	ssc_p = &ssc_info[cpu_dai->id];
	ssc_p = &ssc_info[pdev->id];

	/* Save the status register before disabling transmit and receive */
	ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
@@ -852,12 +860,13 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
{
	struct atmel_ssc_info *ssc_p;
	struct platform_device *pdev = to_platform_device(cpu_dai->dev);
	u32 cr;

	if (!cpu_dai->active)
		return 0;

	ssc_p = &ssc_info[cpu_dai->id];
	ssc_p = &ssc_info[pdev->id];

	/* restore SSC register settings */
	ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
+64 −220
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/slab.h>

#include <sound/core.h>
@@ -46,55 +47,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>

/* Clock registers */
#define BCM2835_CLK_PCMCTL_REG  0x00
#define BCM2835_CLK_PCMDIV_REG  0x04

/* Clock register settings */
#define BCM2835_CLK_PASSWD		(0x5a000000)
#define BCM2835_CLK_PASSWD_MASK	(0xff000000)
#define BCM2835_CLK_MASH(v)		((v) << 9)
#define BCM2835_CLK_FLIP		BIT(8)
#define BCM2835_CLK_BUSY		BIT(7)
#define BCM2835_CLK_KILL		BIT(5)
#define BCM2835_CLK_ENAB		BIT(4)
#define BCM2835_CLK_SRC(v)		(v)

#define BCM2835_CLK_SHIFT		(12)
#define BCM2835_CLK_DIVI(v)		((v) << BCM2835_CLK_SHIFT)
#define BCM2835_CLK_DIVF(v)		(v)
#define BCM2835_CLK_DIVF_MASK		(0xFFF)

enum {
	BCM2835_CLK_MASH_0 = 0,
	BCM2835_CLK_MASH_1,
	BCM2835_CLK_MASH_2,
	BCM2835_CLK_MASH_3,
};

enum {
	BCM2835_CLK_SRC_GND = 0,
	BCM2835_CLK_SRC_OSC,
	BCM2835_CLK_SRC_DBG0,
	BCM2835_CLK_SRC_DBG1,
	BCM2835_CLK_SRC_PLLA,
	BCM2835_CLK_SRC_PLLC,
	BCM2835_CLK_SRC_PLLD,
	BCM2835_CLK_SRC_HDMI,
};

/* Most clocks are not useable (freq = 0) */
static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = {
	[BCM2835_CLK_SRC_GND]		= 0,
	[BCM2835_CLK_SRC_OSC]		= 19200000,
	[BCM2835_CLK_SRC_DBG0]		= 0,
	[BCM2835_CLK_SRC_DBG1]		= 0,
	[BCM2835_CLK_SRC_PLLA]		= 0,
	[BCM2835_CLK_SRC_PLLC]		= 0,
	[BCM2835_CLK_SRC_PLLD]		= 500000000,
	[BCM2835_CLK_SRC_HDMI]		= 0,
};

/* I2S registers */
#define BCM2835_I2S_CS_A_REG		0x00
#define BCM2835_I2S_FIFO_A_REG		0x04
@@ -158,10 +110,6 @@ static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = {
#define BCM2835_I2S_INT_RXR		BIT(1)
#define BCM2835_I2S_INT_TXW		BIT(0)

/* I2S DMA interface */
/* FIXME: Needs IOMMU support */
#define BCM2835_VCMMU_SHIFT		(0x7E000000 - 0x20000000)

/* General device struct */
struct bcm2835_i2s_dev {
	struct device				*dev;
@@ -170,20 +118,22 @@ struct bcm2835_i2s_dev {
	unsigned int				bclk_ratio;

	struct regmap				*i2s_regmap;
	struct regmap *clk_regmap;
	struct clk				*clk;
	bool					clk_prepared;
};

static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
{
	/* Start the clock if in master mode */
	unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;

	if (dev->clk_prepared)
		return;

	switch (master) {
	case SND_SOC_DAIFMT_CBS_CFS:
	case SND_SOC_DAIFMT_CBS_CFM:
		regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
			BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
			BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
		clk_prepare_enable(dev->clk);
		dev->clk_prepared = true;
		break;
	default:
		break;
@@ -192,28 +142,9 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)

static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev)
{
	uint32_t clkreg;
	int timeout = 1000;

	/* Stop clock */
	regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
			BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
			BCM2835_CLK_PASSWD);

	/* Wait for the BUSY flag going down */
	while (--timeout) {
		regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
		if (!(clkreg & BCM2835_CLK_BUSY))
			break;
	}

	if (!timeout) {
		/* KILL the clock */
		dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n");
		regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
			BCM2835_CLK_KILL | BCM2835_CLK_PASSWD_MASK,
			BCM2835_CLK_KILL | BCM2835_CLK_PASSWD);
	}
	if (dev->clk_prepared)
		clk_disable_unprepare(dev->clk);
	dev->clk_prepared = false;
}

static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
@@ -223,8 +154,7 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
	uint32_t syncval;
	uint32_t csreg;
	uint32_t i2s_active_state;
	uint32_t clkreg;
	uint32_t clk_active_state;
	bool clk_was_prepared;
	uint32_t off;
	uint32_t clr;

@@ -238,15 +168,10 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
	regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
	i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON);

	regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
	clk_active_state = clkreg & BCM2835_CLK_ENAB;

	/* Start clock if not running */
	if (!clk_active_state) {
		regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
			BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
			BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
	}
	clk_was_prepared = dev->clk_prepared;
	if (!clk_was_prepared)
		bcm2835_i2s_start_clock(dev);

	/* Stop I2S module */
	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0);
@@ -280,7 +205,7 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
		dev_err(dev->dev, "I2S SYNC error!\n");

	/* Stop clock if it was not running before */
	if (!clk_active_state)
	if (!clk_was_prepared)
		bcm2835_i2s_stop_clock(dev);

	/* Restore I2S state */
@@ -309,19 +234,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
				 struct snd_soc_dai *dai)
{
	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);

	unsigned int sampling_rate = params_rate(params);
	unsigned int data_length, data_delay, bclk_ratio;
	unsigned int ch1pos, ch2pos, mode, format;
	unsigned int mash = BCM2835_CLK_MASH_1;
	unsigned int divi, divf, target_frequency;
	int clk_src = -1;
	unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
	bool bit_master =	(master == SND_SOC_DAIFMT_CBS_CFS
					|| master == SND_SOC_DAIFMT_CBS_CFM);

	bool frame_master =	(master == SND_SOC_DAIFMT_CBS_CFS
					|| master == SND_SOC_DAIFMT_CBM_CFS);
	uint32_t csreg;

	/*
@@ -343,11 +258,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		data_length = 16;
		bclk_ratio = 40;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		data_length = 32;
		bclk_ratio = 80;
		break;
	default:
		return -EINVAL;
@@ -356,69 +269,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
	/* If bclk_ratio already set, use that one. */
	if (dev->bclk_ratio)
		bclk_ratio = dev->bclk_ratio;

	/*
	 * Clock Settings
	 *
	 * The target frequency of the bit clock is
	 *	sampling rate * frame length
	 *
	 * Integer mode:
	 * Sampling rates that are multiples of 8000 kHz
	 * can be driven by the oscillator of 19.2 MHz
	 * with an integer divider as long as the frame length
	 * is an integer divider of 19200000/8000=2400 as set up above.
	 * This is no longer possible if the sampling rate
	 * is too high (e.g. 192 kHz), because the oscillator is too slow.
	 *
	 * MASH mode:
	 * For all other sampling rates, it is not possible to
	 * have an integer divider. Approximate the clock
	 * with the MASH module that induces a slight frequency
	 * variance. To minimize that it is best to have the fastest
	 * clock here. That is PLLD with 500 MHz.
	 */
	target_frequency = sampling_rate * bclk_ratio;
	clk_src = BCM2835_CLK_SRC_OSC;
	mash = BCM2835_CLK_MASH_0;

	if (bcm2835_clk_freq[clk_src] % target_frequency == 0
			&& bit_master && frame_master) {
		divi = bcm2835_clk_freq[clk_src] / target_frequency;
		divf = 0;
	} else {
		uint64_t dividend;

		if (!dev->bclk_ratio) {
			/*
			 * Overwrite bclk_ratio, because the
			 * above trick is not needed or can
			 * not be used.
			 */
	else
		/* otherwise calculate a fitting block ratio */
		bclk_ratio = 2 * data_length;
		}

		target_frequency = sampling_rate * bclk_ratio;

		clk_src = BCM2835_CLK_SRC_PLLD;
		mash = BCM2835_CLK_MASH_1;

		dividend = bcm2835_clk_freq[clk_src];
		dividend <<= BCM2835_CLK_SHIFT;
		do_div(dividend, target_frequency);
		divi = dividend >> BCM2835_CLK_SHIFT;
		divf = dividend & BCM2835_CLK_DIVF_MASK;
	}

	/* Set clock divider */
	regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
			| BCM2835_CLK_DIVI(divi)
			| BCM2835_CLK_DIVF(divf));

	/* Setup clock, but don't start it yet */
	regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
			| BCM2835_CLK_MASH(mash)
			| BCM2835_CLK_SRC(clk_src));
	/* set target clock rate*/
	clk_set_rate(dev->clk, sampling_rate * bclk_ratio);

	/* Setup the frame format */
	format = BCM2835_I2S_CHEN;
@@ -692,7 +548,7 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
	.trigger	= bcm2835_i2s_trigger,
	.hw_params	= bcm2835_i2s_hw_params,
	.set_fmt	= bcm2835_i2s_set_dai_fmt,
	.set_bclk_ratio	= bcm2835_i2s_set_dai_bclk_ratio
	.set_bclk_ratio	= bcm2835_i2s_set_dai_bclk_ratio,
};

static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
@@ -750,18 +606,7 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
	};
}

static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg)
{
	switch (reg) {
	case BCM2835_CLK_PCMCTL_REG:
		return true;
	default:
		return false;
	};
}

static const struct regmap_config bcm2835_regmap_config[] = {
	{
static const struct regmap_config bcm2835_regmap_config = {
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
@@ -769,15 +614,6 @@ static const struct regmap_config bcm2835_regmap_config[] = {
	.precious_reg = bcm2835_i2s_precious_reg,
	.volatile_reg = bcm2835_i2s_volatile_reg,
	.cache_type = REGCACHE_RBTREE,
	},
	{
		.reg_bits = 32,
		.reg_stride = 4,
		.val_bits = 32,
		.max_register = BCM2835_CLK_PCMDIV_REG,
		.volatile_reg = bcm2835_clk_volatile_reg,
		.cache_type = REGCACHE_RBTREE,
	},
};

static const struct snd_soc_component_driver bcm2835_i2s_component = {
@@ -787,42 +623,50 @@ static const struct snd_soc_component_driver bcm2835_i2s_component = {
static int bcm2835_i2s_probe(struct platform_device *pdev)
{
	struct bcm2835_i2s_dev *dev;
	int i;
	int ret;
	struct regmap *regmap[2];
	struct resource *mem[2];

	/* Request both ioareas */
	for (i = 0; i <= 1; i++) {
	struct resource *mem;
	void __iomem *base;

		mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
		base = devm_ioremap_resource(&pdev->dev, mem[i]);
		if (IS_ERR(base))
			return PTR_ERR(base);

		regmap[i] = devm_regmap_init_mmio(&pdev->dev, base,
					    &bcm2835_regmap_config[i]);
		if (IS_ERR(regmap[i]))
			return PTR_ERR(regmap[i]);
	}
	const __be32 *addr;
	dma_addr_t dma_base;

	dev = devm_kzalloc(&pdev->dev, sizeof(*dev),
			   GFP_KERNEL);
	if (!dev)
		return -ENOMEM;

	dev->i2s_regmap = regmap[0];
	dev->clk_regmap = regmap[1];
	/* get the clock */
	dev->clk_prepared = false;
	dev->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(dev->clk)) {
		dev_err(&pdev->dev, "could not get clk: %ld\n",
			PTR_ERR(dev->clk));
		return PTR_ERR(dev->clk);
	}

	/* Request ioarea */
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	base = devm_ioremap_resource(&pdev->dev, mem);
	if (IS_ERR(base))
		return PTR_ERR(base);

	dev->i2s_regmap = devm_regmap_init_mmio(&pdev->dev, base,
				&bcm2835_regmap_config);
	if (IS_ERR(dev->i2s_regmap))
		return PTR_ERR(dev->i2s_regmap);

	/* Set the DMA address - we have to parse DT ourselves */
	addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
	if (!addr) {
		dev_err(&pdev->dev, "could not get DMA-register address\n");
		return -EINVAL;
	}
	dma_base = be32_to_cpup(addr);

	/* Set the DMA address */
	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
		(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
					  + BCM2835_VCMMU_SHIFT;
		dma_base + BCM2835_I2S_FIFO_A_REG;

	dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
		(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
					  + BCM2835_VCMMU_SHIFT;
		dma_base + BCM2835_I2S_FIFO_A_REG;

	/* Set the bus width */
	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
+8 −2
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ struct cs42xx8_priv {

	bool slave_mode;
	unsigned long sysclk;
	u32 tx_channels;
};

/* -127.5dB to 0dB with step of 0.5dB */
@@ -257,6 +258,9 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
	u32 ratio = cs42xx8->sysclk / params_rate(params);
	u32 i, fm, val, mask;

	if (tx)
		cs42xx8->tx_channels = params_channels(params);

	for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
		if (cs42xx8_ratios[i].ratio == ratio)
			break;
@@ -283,9 +287,11 @@ static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;
	struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
	u8 dac_unmute = cs42xx8->tx_channels ?
		        ~((0x1 << cs42xx8->tx_channels) - 1) : 0;

	regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
			   CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
		     mute ? CS42XX8_DACMUTE_ALL : dac_unmute);

	return 0;
}