Commit a391dbe0 authored by Mark Brown's avatar Mark Brown

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
...@@ -34,6 +34,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num) ...@@ -34,6 +34,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
if (ssc->pdev->dev.of_node) { if (ssc->pdev->dev.of_node) {
if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc") if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc")
== ssc_num) { == ssc_num) {
ssc->pdev->id = ssc_num;
ssc_valid = 1; ssc_valid = 1;
break; break;
} }
......
...@@ -285,7 +285,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, ...@@ -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, static int atmel_ssc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) 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; struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask; int dir, dir_mask;
int ret; int ret;
...@@ -346,7 +347,8 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, ...@@ -346,7 +347,8 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) 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; struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask; int dir, dir_mask;
...@@ -392,7 +394,8 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, ...@@ -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, static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt) 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; ssc_p->daifmt = fmt;
return 0; return 0;
...@@ -404,7 +407,8 @@ static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, ...@@ -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, static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div) 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) { switch (div_id) {
case ATMEL_SSC_CMR_DIV: case ATMEL_SSC_CMR_DIV:
...@@ -445,7 +449,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ...@@ -445,7 +449,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) 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 atmel_ssc_info *ssc_p = &ssc_info[id];
struct ssc_device *ssc = ssc_p->ssc; struct ssc_device *ssc = ssc_p->ssc;
struct atmel_pcm_dma_params *dma_params; struct atmel_pcm_dma_params *dma_params;
...@@ -772,7 +777,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ...@@ -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, static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) 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; struct atmel_pcm_dma_params *dma_params;
int dir; int dir;
...@@ -795,7 +801,8 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, ...@@ -795,7 +801,8 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
static int atmel_ssc_trigger(struct snd_pcm_substream *substream, static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) 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; struct atmel_pcm_dma_params *dma_params;
int dir; int dir;
...@@ -824,11 +831,12 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream, ...@@ -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) static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
{ {
struct atmel_ssc_info *ssc_p; struct atmel_ssc_info *ssc_p;
struct platform_device *pdev = to_platform_device(cpu_dai->dev);
if (!cpu_dai->active) if (!cpu_dai->active)
return 0; return 0;
ssc_p = &ssc_info[cpu_dai->id]; ssc_p = &ssc_info[pdev->id];
/* Save the status register before disabling transmit and receive */ /* Save the status register before disabling transmit and receive */
ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); 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) ...@@ -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) static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
{ {
struct atmel_ssc_info *ssc_p; struct atmel_ssc_info *ssc_p;
struct platform_device *pdev = to_platform_device(cpu_dai->dev);
u32 cr; u32 cr;
if (!cpu_dai->active) if (!cpu_dai->active)
return 0; return 0;
ssc_p = &ssc_info[cpu_dai->id]; ssc_p = &ssc_info[pdev->id];
/* restore SSC register settings */ /* restore SSC register settings */
ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <sound/core.h> #include <sound/core.h>
...@@ -46,55 +47,6 @@ ...@@ -46,55 +47,6 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.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 */ /* I2S registers */
#define BCM2835_I2S_CS_A_REG 0x00 #define BCM2835_I2S_CS_A_REG 0x00
#define BCM2835_I2S_FIFO_A_REG 0x04 #define BCM2835_I2S_FIFO_A_REG 0x04
...@@ -158,10 +110,6 @@ static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = { ...@@ -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_RXR BIT(1)
#define BCM2835_I2S_INT_TXW BIT(0) #define BCM2835_I2S_INT_TXW BIT(0)
/* I2S DMA interface */
/* FIXME: Needs IOMMU support */
#define BCM2835_VCMMU_SHIFT (0x7E000000 - 0x20000000)
/* General device struct */ /* General device struct */
struct bcm2835_i2s_dev { struct bcm2835_i2s_dev {
struct device *dev; struct device *dev;
...@@ -169,21 +117,23 @@ struct bcm2835_i2s_dev { ...@@ -169,21 +117,23 @@ struct bcm2835_i2s_dev {
unsigned int fmt; unsigned int fmt;
unsigned int bclk_ratio; unsigned int bclk_ratio;
struct regmap *i2s_regmap; 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) 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; unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
if (dev->clk_prepared)
return;
switch (master) { switch (master) {
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_CBS_CFM: case SND_SOC_DAIFMT_CBS_CFM:
regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, clk_prepare_enable(dev->clk);
BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, dev->clk_prepared = true;
BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
break; break;
default: default:
break; break;
...@@ -192,28 +142,9 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) ...@@ -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) static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev)
{ {
uint32_t clkreg; if (dev->clk_prepared)
int timeout = 1000; clk_disable_unprepare(dev->clk);
dev->clk_prepared = false;
/* 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);
}
} }
static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, 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, ...@@ -223,8 +154,7 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
uint32_t syncval; uint32_t syncval;
uint32_t csreg; uint32_t csreg;
uint32_t i2s_active_state; uint32_t i2s_active_state;
uint32_t clkreg; bool clk_was_prepared;
uint32_t clk_active_state;
uint32_t off; uint32_t off;
uint32_t clr; uint32_t clr;
...@@ -238,15 +168,10 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, ...@@ -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); regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON); 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 */ /* Start clock if not running */
if (!clk_active_state) { clk_was_prepared = dev->clk_prepared;
regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, if (!clk_was_prepared)
BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, bcm2835_i2s_start_clock(dev);
BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
}
/* Stop I2S module */ /* Stop I2S module */
regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0); 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, ...@@ -280,7 +205,7 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
dev_err(dev->dev, "I2S SYNC error!\n"); dev_err(dev->dev, "I2S SYNC error!\n");
/* Stop clock if it was not running before */ /* Stop clock if it was not running before */
if (!clk_active_state) if (!clk_was_prepared)
bcm2835_i2s_stop_clock(dev); bcm2835_i2s_stop_clock(dev);
/* Restore I2S state */ /* Restore I2S state */
...@@ -309,19 +234,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -309,19 +234,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
unsigned int sampling_rate = params_rate(params); unsigned int sampling_rate = params_rate(params);
unsigned int data_length, data_delay, bclk_ratio; unsigned int data_length, data_delay, bclk_ratio;
unsigned int ch1pos, ch2pos, mode, format; 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; uint32_t csreg;
/* /*
...@@ -343,11 +258,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -343,11 +258,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
data_length = 16; data_length = 16;
bclk_ratio = 40;
break; break;
case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S32_LE:
data_length = 32; data_length = 32;
bclk_ratio = 80;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -356,69 +269,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, ...@@ -356,69 +269,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
/* If bclk_ratio already set, use that one. */ /* If bclk_ratio already set, use that one. */
if (dev->bclk_ratio) if (dev->bclk_ratio)
bclk_ratio = dev->bclk_ratio; bclk_ratio = dev->bclk_ratio;
else
/* otherwise calculate a fitting block ratio */
bclk_ratio = 2 * data_length;
/* /* set target clock rate*/
* Clock Settings clk_set_rate(dev->clk, sampling_rate * bclk_ratio);
*
* 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.
*/
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));
/* Setup the frame format */ /* Setup the frame format */
format = BCM2835_I2S_CHEN; format = BCM2835_I2S_CHEN;
...@@ -692,7 +548,7 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { ...@@ -692,7 +548,7 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.trigger = bcm2835_i2s_trigger, .trigger = bcm2835_i2s_trigger,
.hw_params = bcm2835_i2s_hw_params, .hw_params = bcm2835_i2s_hw_params,
.set_fmt = bcm2835_i2s_set_dai_fmt, .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) static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
...@@ -750,34 +606,14 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg) ...@@ -750,34 +606,14 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
}; };
} }
static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg) static const struct regmap_config bcm2835_regmap_config = {
{ .reg_bits = 32,
switch (reg) { .reg_stride = 4,
case BCM2835_CLK_PCMCTL_REG: .val_bits = 32,
return true; .max_register = BCM2835_I2S_GRAY_REG,
default: .precious_reg = bcm2835_i2s_precious_reg,
return false; .volatile_reg = bcm2835_i2s_volatile_reg,
}; .cache_type = REGCACHE_RBTREE,
}
static const struct regmap_config bcm2835_regmap_config[] = {
{
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = BCM2835_I2S_GRAY_REG,
.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 = { static const struct snd_soc_component_driver bcm2835_i2s_component = {
...@@ -787,42 +623,50 @@ 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) static int bcm2835_i2s_probe(struct platform_device *pdev)
{ {
struct bcm2835_i2s_dev *dev; struct bcm2835_i2s_dev *dev;
int i;
int ret; int ret;
struct regmap *regmap[2]; struct resource *mem;
struct resource *mem[2]; void __iomem *base;
const __be32 *addr;
/* Request both ioareas */ dma_addr_t dma_base;
for (i = 0; i <= 1; i++) {
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]);
}
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), dev = devm_kzalloc(&pdev->dev, sizeof(*dev),
GFP_KERNEL); GFP_KERNEL);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
dev->i2s_regmap = regmap[0]; /* get the clock */
dev->clk_regmap = regmap[1]; 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 = dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG dma_base + BCM2835_I2S_FIFO_A_REG;
+ BCM2835_VCMMU_SHIFT;
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG dma_base + BCM2835_I2S_FIFO_A_REG;
+ BCM2835_VCMMU_SHIFT;
/* Set the bus width */ /* Set the bus width */
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
......
...@@ -44,6 +44,7 @@ struct cs42xx8_priv { ...@@ -44,6 +44,7 @@ struct cs42xx8_priv {
bool slave_mode; bool slave_mode;
unsigned long sysclk; unsigned long sysclk;
u32 tx_channels;
}; };
/* -127.5dB to 0dB with step of 0.5dB */ /* -127.5dB to 0dB with step of 0.5dB */
...@@ -257,6 +258,9 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, ...@@ -257,6 +258,9 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
u32 ratio = cs42xx8->sysclk / params_rate(params); u32 ratio = cs42xx8->sysclk / params_rate(params);
u32 i, fm, val, mask; u32 i, fm, val, mask;
if (tx)
cs42xx8->tx_channels = params_channels(params);
for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
if (cs42xx8_ratios[i].ratio == ratio) if (cs42xx8_ratios[i].ratio == ratio)
break; break;
...@@ -283,9 +287,11 @@ static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) ...@@ -283,9 +287,11 @@ static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(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, regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0); mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment