buf->area = dma_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
- (void *)buf->area, (void *)buf->addr, size);
+ (void *)buf->area, (void *)(long)buf->addr, size);
if (!buf->area)
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(atmel_pcm_mmap);
-static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32);
-
int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &atmel_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/soc-dapm.h>
+ #include <linux/regmap.h>
#include "mc13783.h"
- #define MC13783_AUDIO_RX0 36
- #define MC13783_AUDIO_RX1 37
- #define MC13783_AUDIO_TX 38
- #define MC13783_SSI_NETWORK 39
- #define MC13783_AUDIO_CODEC 40
- #define MC13783_AUDIO_DAC 41
-
#define AUDIO_RX0_ALSPEN (1 << 5)
#define AUDIO_RX0_ALSPSEL (1 << 7)
#define AUDIO_RX0_ADDCDC (1 << 21)
struct mc13783_priv {
struct mc13xxx *mc13xxx;
+ struct regmap *regmap;
enum mc13783_ssi_port adc_ssi_port;
enum mc13783_ssi_port dac_ssi_port;
};
- static unsigned int mc13783_read(struct snd_soc_codec *codec,
- unsigned int reg)
- {
- struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- unsigned int value = 0;
-
- mc13xxx_lock(priv->mc13xxx);
-
- mc13xxx_reg_read(priv->mc13xxx, reg, &value);
-
- mc13xxx_unlock(priv->mc13xxx);
-
- return value;
- }
-
- static int mc13783_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
- {
- struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- mc13xxx_lock(priv->mc13xxx);
-
- ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
-
- /* include errata fix for spi audio problems */
- if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC)
- ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
-
- mc13xxx_unlock(priv->mc13xxx);
-
- return ret;
- }
-
/* Mapping between sample rates and register value */
static unsigned int mc13783_rates[] = {
8000, 11025, 12000, 16000,
break;
default:
return -EINVAL;
- };
+ }
snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
static const struct snd_kcontrol_new samp_ctl =
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
+ static const char * const speaker_amp_source_text[] = {
+ "CODEC", "Right"
+ };
+ static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
+ speaker_amp_source_text);
+ static const struct snd_kcontrol_new speaker_amp_source_mux =
+ SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
+
+ static const char * const headset_amp_source_text[] = {
+ "CODEC", "Mixer"
+ };
+
+ static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
+ headset_amp_source_text);
+ static const struct snd_kcontrol_new headset_amp_source_mux =
+ SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
+
+ static const struct snd_kcontrol_new cdcout_ctl =
+ SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0);
+
+ static const struct snd_kcontrol_new adc_bypass_ctl =
+ SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0);
+
static const struct snd_kcontrol_new lamp_ctl =
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);
SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
&right_input_mux),
+ SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
+ &speaker_amp_source_mux),
+
+ SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0,
+ &headset_amp_source_mux),
+
SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),
SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0,
+ &adc_bypass_ctl),
+
/* Output */
SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("RXOUTR"),
SND_SOC_DAPM_OUTPUT("HSL"),
SND_SOC_DAPM_OUTPUT("HSR"),
+ SND_SOC_DAPM_OUTPUT("LSPL"),
SND_SOC_DAPM_OUTPUT("LSP"),
SND_SOC_DAPM_OUTPUT("SP"),
+ SND_SOC_DAPM_OUTPUT("CDCOUT"),
- SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl),
+ SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0,
+ &cdcout_ctl),
+ SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0,
+ &samp_ctl),
SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,
&hlamp_ctl),
{ "ADC", NULL, "PGA Right Input"},
{ "ADC", NULL, "ADC_Reset"},
+ { "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" },
+
+ { "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"},
+ { "Speaker Amp Source MUX", "Right", "DAC PGA"},
+
+ { "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"},
+ { "Headset Amp Source MUX", "Mixer", "DAC PGA"},
+
/* Output */
{ "HSL", NULL, "Headset Amp Left" },
{ "HSR", NULL, "Headset Amp Right"},
{ "RXOUTL", NULL, "Line out Amp Left"},
{ "RXOUTR", NULL, "Line out Amp Right"},
- { "SP", NULL, "Speaker Amp"},
- { "Speaker Amp", NULL, "DAC PGA"},
- { "LSP", NULL, "DAC PGA"},
- { "Headset Amp Left", NULL, "DAC PGA"},
- { "Headset Amp Right", NULL, "DAC PGA"},
+ { "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"},
+ { "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"},
+ { "HSL", "Headset Amp Left", "Headset Amp Source MUX"},
+ { "HSR", "Headset Amp Right", "Headset Amp Source MUX"},
{ "Line out Amp Left", NULL, "DAC PGA"},
{ "Line out Amp Right", NULL, "DAC PGA"},
{ "DAC PGA", NULL, "DAC"},
{ "DAC", NULL, "DAC_E"},
+ { "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},
};
static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
static struct snd_kcontrol_new mc13783_control_list[] = {
SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
+ SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),
SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
+
+ SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0),
+ SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0),
+ SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0),
+ SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0),
+
+ SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0),
+ SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0),
+
+ SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0),
+ SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0),
+
+ SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0),
+ SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0),
+
+ SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0),
+ SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),
};
static int mc13783_probe(struct snd_soc_codec *codec)
{
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
- mc13xxx_lock(priv->mc13xxx);
+ codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
/* these are the reset values */
mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
0, AUDIO_SSI_SEL);
- mc13xxx_unlock(priv->mc13xxx);
-
return 0;
}
{
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- mc13xxx_lock(priv->mc13xxx);
-
/* Make sure VAUDIOON is off */
mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
- mc13xxx_unlock(priv->mc13xxx);
-
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
.probe = mc13783_probe,
.remove = mc13783_remove,
- .read = mc13783_read,
- .write = mc13783_write,
.controls = mc13783_control_list,
.num_controls = ARRAY_SIZE(mc13783_control_list),
.dapm_widgets = mc13783_dapm_widgets,
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
+ #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
unsigned int mclk, sclk;
unsigned int format;
bool deemph;
+ unsigned int charge_period;
+ unsigned int pwm_start_mid_z;
/* Current sample rate for de-emphasis control */
int rate;
/* GPIO driving Reset pin, if any */
default:
dev_err(codec->dev, "Invalid bit width\n");
return -EINVAL;
- };
+ }
ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
if (ret < 0)
return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
}
+ static void tas5086_reset(struct tas5086_private *priv)
+ {
+ if (gpio_is_valid(priv->gpio_nreset)) {
+ /* Reset codec - minimum assertion time is 400ns */
+ gpio_direction_output(priv->gpio_nreset, 0);
+ udelay(1);
+ gpio_set_value(priv->gpio_nreset, 1);
+
+ /* Codec needs ~15ms to wake up */
+ msleep(15);
+ }
+ }
+
+ /* charge period values in microseconds */
+ static const int tas5086_charge_period[] = {
+ 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
+ 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
+ 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
+ };
+
+ static int tas5086_init(struct device *dev, struct tas5086_private *priv)
+ {
+ int ret, i;
+
+ /*
+ * If any of the channels is configured to start in Mid-Z mode,
+ * configure 'part 1' of the PWM starts to use Mid-Z, and tell
+ * all configured mid-z channels to start start under 'part 1'.
+ */
+ if (priv->pwm_start_mid_z)
+ regmap_write(priv->regmap, TAS5086_PWM_START,
+ TAS5086_PWM_START_MIDZ_FOR_START_1 |
+ priv->pwm_start_mid_z);
+
+ /* lookup and set split-capacitor charge period */
+ if (priv->charge_period == 0) {
+ regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
+ } else {
+ i = index_in_array(tas5086_charge_period,
+ ARRAY_SIZE(tas5086_charge_period),
+ priv->charge_period);
+ if (i >= 0)
+ regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
+ i + 0x08);
+ else
+ dev_warn(dev,
+ "Invalid split-cap charge period of %d ns.\n",
+ priv->charge_period);
+ }
+
+ /* enable factory trim */
+ ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
+ if (ret < 0)
+ return ret;
+
+ /* start all channels */
+ ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+ if (ret < 0)
+ return ret;
+
+ /* mute all channels for now */
+ ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
+ TAS5086_SOFT_MUTE_ALL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ }
+
/* TAS5086 controls */
static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
};
#ifdef CONFIG_PM
+ static int tas5086_soc_suspend(struct snd_soc_codec *codec)
+ {
+ struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ /* Shut down all channels */
+ ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ }
+
static int tas5086_soc_resume(struct snd_soc_codec *codec)
{
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ tas5086_reset(priv);
+ regcache_mark_dirty(priv->regmap);
+
+ ret = tas5086_init(codec->dev, priv);
+ if (ret < 0)
+ return ret;
+
+ ret = regcache_sync(priv->regmap);
+ if (ret < 0)
+ return ret;
- /* Restore codec state */
- return regcache_sync(priv->regmap);
+ return 0;
}
#else
+ #define tas5086_soc_suspend NULL
#define tas5086_soc_resume NULL
#endif /* CONFIG_PM */
MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
#endif
- /* charge period values in microseconds */
- static const int tas5086_charge_period[] = {
- 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
- 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
- 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
- };
-
static int tas5086_probe(struct snd_soc_codec *codec)
{
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
- int charge_period = 1300000; /* hardware default is 1300 ms */
- u8 pwm_start_mid_z = 0;
int i, ret;
+ priv->pwm_start_mid_z = 0;
+ priv->charge_period = 1300000; /* hardware default is 1300 ms */
+
if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
struct device_node *of_node = codec->dev->of_node;
- of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+
+ of_property_read_u32(of_node, "ti,charge-period",
+ &priv->charge_period);
for (i = 0; i < 6; i++) {
char name[25];
"ti,mid-z-channel-%d", i + 1);
if (of_get_property(of_node, name, NULL) != NULL)
- pwm_start_mid_z |= 1 << i;
+ priv->pwm_start_mid_z |= 1 << i;
}
}
- /*
- * If any of the channels is configured to start in Mid-Z mode,
- * configure 'part 1' of the PWM starts to use Mid-Z, and tell
- * all configured mid-z channels to start start under 'part 1'.
- */
- if (pwm_start_mid_z)
- regmap_write(priv->regmap, TAS5086_PWM_START,
- TAS5086_PWM_START_MIDZ_FOR_START_1 |
- pwm_start_mid_z);
-
- /* lookup and set split-capacitor charge period */
- if (charge_period == 0) {
- regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
- } else {
- i = index_in_array(tas5086_charge_period,
- ARRAY_SIZE(tas5086_charge_period),
- charge_period);
- if (i >= 0)
- regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
- i + 0x08);
- else
- dev_warn(codec->dev,
- "Invalid split-cap charge period of %d ns.\n",
- charge_period);
- }
-
- /* enable factory trim */
- ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
- if (ret < 0)
- return ret;
-
- /* start all channels */
- ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+ ret = tas5086_init(codec->dev, priv);
if (ret < 0)
return ret;
if (ret < 0)
return ret;
- /* mute all channels for now */
- ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
- TAS5086_SOFT_MUTE_ALL);
- if (ret < 0)
- return ret;
-
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
.probe = tas5086_probe,
.remove = tas5086_remove,
+ .suspend = tas5086_soc_suspend,
.resume = tas5086_soc_resume,
.controls = tas5086_controls,
.num_controls = ARRAY_SIZE(tas5086_controls),
if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
gpio_nreset = -EINVAL;
- if (gpio_is_valid(gpio_nreset)) {
- /* Reset codec - minimum assertion time is 400ns */
- gpio_direction_output(gpio_nreset, 0);
- udelay(1);
- gpio_set_value(gpio_nreset, 1);
-
- /* Codec needs ~15ms to wake up */
- msleep(15);
- }
-
priv->gpio_nreset = gpio_nreset;
+ tas5086_reset(priv);
/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
goto fail;
}
codec_dev = of_find_i2c_device_by_node(codec_np);
- if (!codec_dev || !codec_dev->driver) {
+ if (!codec_dev || !codec_dev->dev.driver) {
dev_err(&pdev->dev, "failed to find codec platform device\n");
ret = -EINVAL;
goto fail;
data->card.late_probe = imx_wm8962_late_probe;
data->card.set_bias_level = imx_wm8962_set_bias_level;
- ret = snd_soc_register_card(&data->card);
+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
goto clk_fail;
if (!IS_ERR(data->codec_clk))
clk_disable_unprepare(data->codec_clk);
- snd_soc_unregister_card(&data->card);
return 0;
}
#define KIRKWOOD_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE | \
- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \
- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE)
+ SNDRV_PCM_FMTBIT_S32_LE)
static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
{
.fifo_size = 0,
};
-static u64 kirkwood_dma_dmamask = DMA_BIT_MASK(32);
-
static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
{
struct kirkwood_dma_data *priv = dev_id;
* Enable Error interrupts. We're only ack'ing them but
* it's useful for diagnostics
*/
- writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+ writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK);
}
dram = mv_mbus_dram_info();
struct snd_pcm *pcm = rtd->pcm;
int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &kirkwood_dma_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = kirkwood_dma_preallocate_dma_buffer(pcm,
{
int channel;
u32 reg, val;
+ struct tegra30_ahub_cif_conf cif_conf;
channel = find_first_zero_bit(ahub->rx_usage,
TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
tegra30_apbif_write(reg, val);
+ cif_conf.threshold = 0;
+ cif_conf.audio_channels = 2;
+ cif_conf.client_channels = 2;
+ cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.expand = 0;
+ cif_conf.stereo_conv = 0;
+ cif_conf.replicate = 0;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
+ cif_conf.truncate = 0;
+ cif_conf.mono_conv = 0;
+
reg = TEGRA30_AHUB_CIF_RX_CTRL +
(channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
- val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
- TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
- tegra30_apbif_write(reg, val);
+ ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
return 0;
}
{
int channel;
u32 reg, val;
+ struct tegra30_ahub_cif_conf cif_conf;
channel = find_first_zero_bit(ahub->tx_usage,
TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
tegra30_apbif_write(reg, val);
+ cif_conf.threshold = 0;
+ cif_conf.audio_channels = 2;
+ cif_conf.client_channels = 2;
+ cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.expand = 0;
+ cif_conf.stereo_conv = 0;
+ cif_conf.replicate = 0;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
+ cif_conf.truncate = 0;
+ cif_conf.mono_conv = 0;
+
reg = TEGRA30_AHUB_CIF_TX_CTRL +
(channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
- val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
- TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
- tegra30_apbif_write(reg, val);
+ ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
return 0;
}
return true;
default:
break;
- };
+ }
if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
return true;
default:
break;
- };
+ }
if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
static struct tegra30_ahub_soc_data soc_data_tegra30 = {
.clk_list_mask = CLK_LIST_MASK_TEGRA30,
+ .set_audio_cif = tegra30_ahub_set_cif,
};
static struct tegra30_ahub_soc_data soc_data_tegra114 = {
.clk_list_mask = CLK_LIST_MASK_TEGRA114,
+ .set_audio_cif = tegra30_ahub_set_cif,
+ };
+
+ static struct tegra30_ahub_soc_data soc_data_tegra124 = {
+ .clk_list_mask = CLK_LIST_MASK_TEGRA114,
+ .set_audio_cif = tegra124_ahub_set_cif,
};
static const struct of_device_id tegra30_ahub_of_match[] = {
+ { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 },
{ .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 },
{},
}
dev_set_drvdata(&pdev->dev, ahub);
+ ahub->soc_data = soc_data;
ahub->dev = &pdev->dev;
ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
};
module_platform_driver(tegra30_ahub_driver);
+ void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf)
+ {
+ unsigned int value;
+
+ value = (conf->threshold <<
+ TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ ((conf->audio_channels - 1) <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ ((conf->client_channels - 1) <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ (conf->audio_bits <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ (conf->client_bits <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
+ (conf->expand <<
+ TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
+ (conf->stereo_conv <<
+ TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
+ (conf->replicate <<
+ TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
+ (conf->direction <<
+ TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
+ (conf->truncate <<
+ TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
+ (conf->mono_conv <<
+ TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
+
+ regmap_write(regmap, reg, value);
+ }
+ EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
+
+ void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf)
+ {
+ unsigned int value;
+
+ value = (conf->threshold <<
+ TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ ((conf->audio_channels - 1) <<
+ TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ ((conf->client_channels - 1) <<
+ TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ (conf->audio_bits <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ (conf->client_bits <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
+ (conf->expand <<
+ TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
+ (conf->stereo_conv <<
+ TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
+ (conf->replicate <<
+ TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
+ (conf->direction <<
+ TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
+ (conf->truncate <<
+ TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
+ (conf->mono_conv <<
+ TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
+
+ regmap_write(regmap, reg, value);
+ }
+ EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
+
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("Tegra30 AHUB driver");
MODULE_LICENSE("GPL v2");
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+ #include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int mask, val, reg;
int ret, sample_size, srate, i2sclock, bitcnt;
+ struct tegra30_ahub_cif_conf cif_conf;
if (params_channels(params) != 2)
return -EINVAL;
regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val);
- val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
- TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16;
+ cif_conf.threshold = 0;
+ cif_conf.audio_channels = 2;
+ cif_conf.client_channels = 2;
+ cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.expand = 0;
+ cif_conf.stereo_conv = 0;
+ cif_conf.replicate = 0;
+ cif_conf.truncate = 0;
+ cif_conf.mono_conv = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
reg = TEGRA30_I2S_CIF_RX_CTRL;
} else {
- val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
reg = TEGRA30_I2S_CIF_TX_CTRL;
}
- regmap_write(i2s->regmap, reg, val);
+ i2s->soc_data->set_audio_cif(i2s->regmap, reg, &cif_conf);
val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
(1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
return true;
default:
return false;
- };
+ }
}
static bool tegra30_i2s_volatile_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config tegra30_i2s_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+ static const struct tegra30_i2s_soc_data tegra30_i2s_config = {
+ .set_audio_cif = tegra30_ahub_set_cif,
+ };
+
+ static const struct tegra30_i2s_soc_data tegra124_i2s_config = {
+ .set_audio_cif = tegra124_ahub_set_cif,
+ };
+
+ static const struct of_device_id tegra30_i2s_of_match[] = {
+ { .compatible = "nvidia,tegra124-i2s", .data = &tegra124_i2s_config },
+ { .compatible = "nvidia,tegra30-i2s", .data = &tegra30_i2s_config },
+ {},
+ };
+
static int tegra30_i2s_platform_probe(struct platform_device *pdev)
{
struct tegra30_i2s *i2s;
+ const struct of_device_id *match;
u32 cif_ids[2];
struct resource *mem, *memregion;
void __iomem *regs;
}
dev_set_drvdata(&pdev->dev, i2s);
+ match = of_match_device(tegra30_i2s_of_match, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ i2s->soc_data = (struct tegra30_i2s_soc_data *)match->data;
+
i2s->dai = tegra30_i2s_dai_template;
i2s->dai.name = dev_name(&pdev->dev);
}
#endif
- static const struct of_device_id tegra30_i2s_of_match[] = {
- { .compatible = "nvidia,tegra30-i2s", },
- {},
- };
-
static const struct dev_pm_ops tegra30_i2s_pm_ops = {
SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
tegra30_i2s_runtime_resume, NULL)