提交 01954a7b 编写于 作者: M Mark Brown

Merge remote-tracking branches 'asoc/topic/cs4265', 'asoc/topic/cs42l56',...

Merge remote-tracking branches 'asoc/topic/cs4265', 'asoc/topic/cs42l56', 'asoc/topic/cs42xx8', 'asoc/topic/cx20442' and 'asoc/topic/davinci' into asoc-next
CS4265 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "cirrus,cs4265"
- reg : the I2C address of the device for I2C. The I2C address depends on
the state of the AD0 pin. If AD0 is high, the i2c address is 0x4f.
If it is low, the i2c address is 0x4e.
Optional properties:
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the codec starts.
Examples:
codec_ad0_high: cs4265@4f { /* AD0 Pin is high */
compatible = "cirrus,cs4265";
reg = <0x4f>;
};
codec_ad0_low: cs4265@4e { /* AD0 Pin is low */
compatible = "cirrus,cs4265";
reg = <0x4e>;
};
......@@ -47,6 +47,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS42L52 if I2C && INPUT
select SND_SOC_CS42L56 if I2C && INPUT
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4265 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
select SND_SOC_CS42XX8_I2C if I2C
......@@ -338,6 +339,11 @@ config SND_SOC_CS42L73
tristate "Cirrus Logic CS42L73 CODEC"
depends on I2C
config SND_SOC_CS4265
tristate "Cirrus Logic CS4265 CODEC"
depends on I2C
select REGMAP_I2C
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate "Cirrus Logic CS4270 CODEC"
......
......@@ -37,6 +37,7 @@ snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l56-objs := cs42l56.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4265-objs := cs4265.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
snd-soc-cs42xx8-objs := cs42xx8.o
......@@ -204,6 +205,7 @@ obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
......
/*
* cs4265.c -- CS4265 ALSA SoC audio driver
*
* Copyright 2014 Cirrus Logic, Inc.
*
* Author: Paul Handrigan <paul.handrigan@cirrus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "cs4265.h"
struct cs4265_private {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
u8 format;
u32 sysclk;
};
static const struct reg_default cs4265_reg_defaults[] = {
{ CS4265_PWRCTL, 0x0F },
{ CS4265_DAC_CTL, 0x08 },
{ CS4265_ADC_CTL, 0x00 },
{ CS4265_MCLK_FREQ, 0x00 },
{ CS4265_SIG_SEL, 0x40 },
{ CS4265_CHB_PGA_CTL, 0x00 },
{ CS4265_CHA_PGA_CTL, 0x00 },
{ CS4265_ADC_CTL2, 0x19 },
{ CS4265_DAC_CHA_VOL, 0x00 },
{ CS4265_DAC_CHB_VOL, 0x00 },
{ CS4265_DAC_CTL2, 0xC0 },
{ CS4265_SPDIF_CTL1, 0x00 },
{ CS4265_SPDIF_CTL2, 0x00 },
{ CS4265_INT_MASK, 0x00 },
{ CS4265_STATUS_MODE_MSB, 0x00 },
{ CS4265_STATUS_MODE_LSB, 0x00 },
};
static bool cs4265_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS4265_PWRCTL:
case CS4265_DAC_CTL:
case CS4265_ADC_CTL:
case CS4265_MCLK_FREQ:
case CS4265_SIG_SEL:
case CS4265_CHB_PGA_CTL:
case CS4265_CHA_PGA_CTL:
case CS4265_ADC_CTL2:
case CS4265_DAC_CHA_VOL:
case CS4265_DAC_CHB_VOL:
case CS4265_DAC_CTL2:
case CS4265_SPDIF_CTL1:
case CS4265_SPDIF_CTL2:
case CS4265_INT_MASK:
case CS4265_STATUS_MODE_MSB:
case CS4265_STATUS_MODE_LSB:
return true;
default:
return false;
}
}
static bool cs4265_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS4265_INT_STATUS:
return true;
default:
return false;
}
}
static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0);
static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0);
static const char * const digital_input_mux_text[] = {
"SDIN1", "SDIN2"
};
static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7,
digital_input_mux_text);
static const struct snd_kcontrol_new digital_input_mux =
SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum);
static const char * const mic_linein_text[] = {
"MIC", "LINEIN"
};
static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0,
mic_linein_text);
static const char * const cam_mode_text[] = {
"One Byte", "Two Byte"
};
static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5,
cam_mode_text);
static const char * const cam_mono_stereo_text[] = {
"Stereo", "Mono"
};
static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2,
cam_mono_stereo_text);
static const char * const mono_select_text[] = {
"Channel A", "Channel B"
};
static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0,
mono_select_text);
static const struct snd_kcontrol_new mic_linein_mux =
SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum);
static const struct snd_kcontrol_new loopback_ctl =
SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0);
static const struct snd_kcontrol_new spdif_switch =
SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0);
static const struct snd_kcontrol_new dac_switch =
SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0);
static const struct snd_kcontrol_new cs4265_snd_controls[] = {
SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL,
CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv),
SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL,
CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv),
SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1,
1, 0),
SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5,
1, 0),
SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6,
1, 0),
SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7,
1, 0),
SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1,
1, 0),
SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3,
1, 1),
SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7,
1, 0),
SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
6, 1, 0),
SOC_ENUM("C Data Access", cam_mode_enum),
SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
3, 1, 0),
SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
SOC_SINGLE("MMTLR Data Switch", 0,
1, 1, 0),
SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
};
static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("LINEINL"),
SND_SOC_DAPM_INPUT("LINEINR"),
SND_SOC_DAPM_INPUT("MICL"),
SND_SOC_DAPM_INPUT("MICR"),
SND_SOC_DAPM_AIF_OUT("DOUT", NULL, 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL, 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux),
SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1),
SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3,
1, NULL, 0),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM,
0, 0, &digital_input_mux),
SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0,
&loopback_ctl),
SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0,
&spdif_switch),
SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1,
&dac_switch),
SND_SOC_DAPM_AIF_IN("DIN1", NULL, 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0,
SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0,
CS4265_SPDIF_CTL2, 5, 1),
SND_SOC_DAPM_OUTPUT("LINEOUTL"),
SND_SOC_DAPM_OUTPUT("LINEOUTR"),
};
static const struct snd_soc_dapm_route cs4265_audio_map[] = {
{"DIN1", NULL, "DAI1 Playback"},
{"DIN2", NULL, "DAI2 Playback"},
{"SDIN1 Input Mixer", NULL, "DIN1"},
{"SDIN2 Input Mixer", NULL, "DIN2"},
{"Input Mux", "SDIN1", "SDIN1 Input Mixer"},
{"Input Mux", "SDIN2", "SDIN2 Input Mixer"},
{"DAC", "Switch", "Input Mux"},
{"SPDIF", "Switch", "Input Mux"},
{"LINEOUTL", NULL, "DAC"},
{"LINEOUTR", NULL, "DAC"},
{"SPDIFOUT", NULL, "SPDIF"},
{"ADC Mux", "LINEIN", "LINEINL"},
{"ADC Mux", "LINEIN", "LINEINR"},
{"ADC Mux", "MIC", "MICL"},
{"ADC Mux", "MIC", "MICR"},
{"ADC", NULL, "ADC Mux"},
{"DOUT", NULL, "ADC"},
{"DAI1 Capture", NULL, "DOUT"},
{"DAI2 Capture", NULL, "DOUT"},
/* Loopback */
{"Loopback", "Switch", "ADC"},
{"DAC", NULL, "Loopback"},
};
struct cs4265_clk_para {
u32 mclk;
u32 rate;
u8 fm_mode; /* values 1, 2, or 4 */
u8 mclkdiv;
};
static const struct cs4265_clk_para clk_map_table[] = {
/*32k*/
{8192000, 32000, 0, 0},
{12288000, 32000, 0, 1},
{16384000, 32000, 0, 2},
{24576000, 32000, 0, 3},
{32768000, 32000, 0, 4},
/*44.1k*/
{11289600, 44100, 0, 0},
{16934400, 44100, 0, 1},
{22579200, 44100, 0, 2},
{33868000, 44100, 0, 3},
{45158400, 44100, 0, 4},
/*48k*/
{12288000, 48000, 0, 0},
{18432000, 48000, 0, 1},
{24576000, 48000, 0, 2},
{36864000, 48000, 0, 3},
{49152000, 48000, 0, 4},
/*64k*/
{8192000, 64000, 1, 0},
{1228800, 64000, 1, 1},
{1693440, 64000, 1, 2},
{2457600, 64000, 1, 3},
{3276800, 64000, 1, 4},
/* 88.2k */
{11289600, 88200, 1, 0},
{16934400, 88200, 1, 1},
{22579200, 88200, 1, 2},
{33868000, 88200, 1, 3},
{45158400, 88200, 1, 4},
/* 96k */
{12288000, 96000, 1, 0},
{18432000, 96000, 1, 1},
{24576000, 96000, 1, 2},
{36864000, 96000, 1, 3},
{49152000, 96000, 1, 4},
/* 128k */
{8192000, 128000, 2, 0},
{12288000, 128000, 2, 1},
{16934400, 128000, 2, 2},
{24576000, 128000, 2, 3},
{32768000, 128000, 2, 4},
/* 176.4k */
{11289600, 176400, 2, 0},
{16934400, 176400, 2, 1},
{22579200, 176400, 2, 2},
{33868000, 176400, 2, 3},
{49152000, 176400, 2, 4},
/* 192k */
{12288000, 192000, 2, 0},
{18432000, 192000, 2, 1},
{24576000, 192000, 2, 2},
{36864000, 192000, 2, 3},
{49152000, 192000, 2, 4},
};
static int cs4265_get_clk_index(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
if (clk_map_table[i].rate == rate &&
clk_map_table[i].mclk == mclk)
return i;
}
return -EINVAL;
}
static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
int i;
if (clk_id != 0) {
dev_err(codec->dev, "Invalid clk_id %d\n", clk_id);
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
if (clk_map_table[i].mclk == freq) {
cs4265->sysclk = freq;
return 0;
}
}
cs4265->sysclk = 0;
dev_err(codec->dev, "Invalid freq parameter %d\n", freq);
return -EINVAL;
}
static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
u8 iface = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_ADC_MASTER,
CS4265_ADC_MASTER);
break;
case SND_SOC_DAIFMT_CBS_CFS:
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_ADC_MASTER,
0);
break;
default:
return -EINVAL;
}
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
iface |= SND_SOC_DAIFMT_I2S;
break;
case SND_SOC_DAIFMT_RIGHT_J:
iface |= SND_SOC_DAIFMT_RIGHT_J;
break;
case SND_SOC_DAIFMT_LEFT_J:
iface |= SND_SOC_DAIFMT_LEFT_J;
break;
default:
return -EINVAL;
}
cs4265->format = iface;
return 0;
}
static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
if (mute) {
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_MUTE,
CS4265_DAC_CTL_MUTE);
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
CS4265_SPDIF_CTL2_MUTE,
CS4265_SPDIF_CTL2_MUTE);
} else {
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_MUTE,
0);
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
CS4265_SPDIF_CTL2_MUTE,
0);
}
return 0;
}
static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
int index;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK)
== SND_SOC_DAIFMT_RIGHT_J))
return -EINVAL;
index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
if (index >= 0) {
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_ADC_FM, clk_map_table[index].fm_mode);
snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
CS4265_MCLK_FREQ_MASK,
clk_map_table[index].mclkdiv);
} else {
dev_err(codec->dev, "can't get correct mclk\n");
return -EINVAL;
}
switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_DIF, (1 << 4));
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_ADC_DIF, (1 << 4));
snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
CS4265_SPDIF_CTL2_DIF, (1 << 6));
break;
case SND_SOC_DAIFMT_RIGHT_J:
if (params_width(params) == 16) {
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_DIF, (1 << 5));
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_SPDIF_CTL2_DIF, (1 << 7));
} else {
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_DIF, (3 << 5));
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_SPDIF_CTL2_DIF, (1 << 7));
}
break;
case SND_SOC_DAIFMT_LEFT_J:
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_DIF, 0);
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_ADC_DIF, 0);
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_SPDIF_CTL2_DIF, (1 << 6));
break;
default:
return -EINVAL;
}
return 0;
}
static int cs4265_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
snd_soc_update_bits(codec, CS4265_PWRCTL,
CS4265_PWRCTL_PDN, 0);
break;
case SND_SOC_BIAS_STANDBY:
snd_soc_update_bits(codec, CS4265_PWRCTL,
CS4265_PWRCTL_PDN,
CS4265_PWRCTL_PDN);
break;
case SND_SOC_BIAS_OFF:
snd_soc_update_bits(codec, CS4265_PWRCTL,
CS4265_PWRCTL_PDN,
CS4265_PWRCTL_PDN);
break;
}
codec->dapm.bias_level = level;
return 0;
}
#define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
static const struct snd_soc_dai_ops cs4265_ops = {
.hw_params = cs4265_pcm_hw_params,
.digital_mute = cs4265_digital_mute,
.set_fmt = cs4265_set_fmt,
.set_sysclk = cs4265_set_sysclk,
};
static struct snd_soc_dai_driver cs4265_dai[] = {
{
.name = "cs4265-dai1",
.playback = {
.stream_name = "DAI1 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = CS4265_RATES,
.formats = CS4265_FORMATS,
},
.capture = {
.stream_name = "DAI1 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = CS4265_RATES,
.formats = CS4265_FORMATS,
},
.ops = &cs4265_ops,
},
{
.name = "cs4265-dai2",
.playback = {
.stream_name = "DAI2 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = CS4265_RATES,
.formats = CS4265_FORMATS,
},
.capture = {
.stream_name = "DAI2 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = CS4265_RATES,
.formats = CS4265_FORMATS,
},
.ops = &cs4265_ops,
},
};
static const struct snd_soc_codec_driver soc_codec_cs4265 = {
.set_bias_level = cs4265_set_bias_level,
.dapm_widgets = cs4265_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets),
.dapm_routes = cs4265_audio_map,
.num_dapm_routes = ARRAY_SIZE(cs4265_audio_map),
.controls = cs4265_snd_controls,
.num_controls = ARRAY_SIZE(cs4265_snd_controls),
};
static const struct regmap_config cs4265_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = CS4265_MAX_REGISTER,
.reg_defaults = cs4265_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
.readable_reg = cs4265_readable_register,
.volatile_reg = cs4265_volatile_register,
.cache_type = REGCACHE_RBTREE,
};
static int cs4265_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct cs4265_private *cs4265;
int ret = 0;
unsigned int devid = 0;
unsigned int reg;
cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private),
GFP_KERNEL);
if (cs4265 == NULL)
return -ENOMEM;
cs4265->dev = &i2c_client->dev;
cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
if (IS_ERR(cs4265->regmap)) {
ret = PTR_ERR(cs4265->regmap);
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev,
"reset-gpios");
if (IS_ERR(cs4265->reset_gpio)) {
ret = PTR_ERR(cs4265->reset_gpio);
if (ret != -ENOENT && ret != -ENOSYS)
return ret;
cs4265->reset_gpio = NULL;
} else {
ret = gpiod_direction_output(cs4265->reset_gpio, 0);
if (ret)
return ret;
mdelay(1);
gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
}
i2c_set_clientdata(i2c_client, cs4265);
ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, &reg);
devid = reg & CS4265_CHIP_ID_MASK;
if (devid != CS4265_CHIP_ID_VAL) {
ret = -ENODEV;
dev_err(&i2c_client->dev,
"CS4265 Device ID (%X). Expected %X\n",
devid, CS4265_CHIP_ID);
return ret;
}
dev_info(&i2c_client->dev,
"CS4265 Version %x\n",
reg & CS4265_REV_ID_MASK);
regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
ret = snd_soc_register_codec(&i2c_client->dev,
&soc_codec_cs4265, cs4265_dai,
ARRAY_SIZE(cs4265_dai));
return ret;
}
static int cs4265_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
return 0;
}
static const struct of_device_id cs4265_of_match[] = {
{ .compatible = "cirrus,cs4265", },
{ }
};
MODULE_DEVICE_TABLE(of, cs4265_of_match);
static const struct i2c_device_id cs4265_id[] = {
{ "cs4265", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs4265_id);
static struct i2c_driver cs4265_i2c_driver = {
.driver = {
.name = "cs4265",
.owner = THIS_MODULE,
.of_match_table = cs4265_of_match,
},
.id_table = cs4265_id,
.probe = cs4265_i2c_probe,
.remove = cs4265_i2c_remove,
};
module_i2c_driver(cs4265_i2c_driver);
MODULE_DESCRIPTION("ASoC CS4265 driver");
MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>");
MODULE_LICENSE("GPL");
/*
* cs4265.h -- CS4265 ALSA SoC audio driver
*
* Copyright 2014 Cirrus Logic, Inc.
*
* Author: Paul Handrigan <paul.handrigan@cirrus.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __CS4265_H__
#define __CS4265_H__
#define CS4265_CHIP_ID 0x1
#define CS4265_CHIP_ID_VAL 0xD0
#define CS4265_CHIP_ID_MASK 0xF0
#define CS4265_REV_ID_MASK 0x0F
#define CS4265_PWRCTL 0x02
#define CS4265_PWRCTL_PDN 1
#define CS4265_DAC_CTL 0x3
#define CS4265_DAC_CTL_MUTE (1 << 2)
#define CS4265_DAC_CTL_DIF (3 << 4)
#define CS4265_ADC_CTL 0x4
#define CS4265_ADC_MASTER 1
#define CS4265_ADC_DIF (1 << 4)
#define CS4265_ADC_FM (3 << 6)
#define CS4265_MCLK_FREQ 0x5
#define CS4265_MCLK_FREQ_MASK (7 << 4)
#define CS4265_SIG_SEL 0x6
#define CS4265_SIG_SEL_LOOP (1 << 1)
#define CS4265_CHB_PGA_CTL 0x7
#define CS4265_CHA_PGA_CTL 0x8
#define CS4265_ADC_CTL2 0x9
#define CS4265_DAC_CHA_VOL 0xA
#define CS4265_DAC_CHB_VOL 0xB
#define CS4265_DAC_CTL2 0xC
#define CS4265_INT_STATUS 0xD
#define CS4265_INT_MASK 0xE
#define CS4265_STATUS_MODE_MSB 0xF
#define CS4265_STATUS_MODE_LSB 0x10
#define CS4265_SPDIF_CTL1 0x11
#define CS4265_SPDIF_CTL2 0x12
#define CS4265_SPDIF_CTL2_MUTE (1 << 4)
#define CS4265_SPDIF_CTL2_DIF (3 << 6)
#define CS4265_C_DATA_BUFF 0x13
#define CS4265_MAX_REGISTER 0x2A
#endif
......@@ -318,24 +318,32 @@ static const struct soc_enum adca_swap_enum =
ARRAY_SIZE(left_swap_text),
left_swap_text,
swap_values);
static const struct snd_kcontrol_new adca_swap_mux =
SOC_DAPM_ENUM("Route", adca_swap_enum);
static const struct soc_enum pcma_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
ARRAY_SIZE(left_swap_text),
left_swap_text,
swap_values);
static const struct snd_kcontrol_new pcma_swap_mux =
SOC_DAPM_ENUM("Route", pcma_swap_enum);
static const struct soc_enum adcb_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
ARRAY_SIZE(right_swap_text),
right_swap_text,
swap_values);
static const struct snd_kcontrol_new adcb_swap_mux =
SOC_DAPM_ENUM("Route", adcb_swap_enum);
static const struct soc_enum pcmb_swap_enum =
SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
ARRAY_SIZE(right_swap_text),
right_swap_text,
swap_values);
static const struct snd_kcontrol_new pcmb_swap_mux =
SOC_DAPM_ENUM("Route", pcmb_swap_enum);
static const struct snd_kcontrol_new hpa_switch =
SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
......@@ -467,11 +475,6 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
SOC_ENUM("PCMA Swap", pcma_swap_enum),
SOC_ENUM("PCMB Swap", pcmb_swap_enum),
SOC_ENUM("ADCA Swap", adca_swap_enum),
SOC_ENUM("ADCB Swap", adcb_swap_enum),
SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
......@@ -570,6 +573,16 @@ static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0,
&adca_swap_mux),
SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0,
&adcb_swap_mux),
SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0,
&pcma_swap_mux),
SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0,
&pcmb_swap_mux),
SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
......@@ -607,8 +620,19 @@ static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
{"Digital Output Mux", NULL, "ADCA"},
{"Digital Output Mux", NULL, "ADCB"},
{"ADCB", NULL, "ADCB Mux"},
{"ADCA", NULL, "ADCA Mux"},
{"ADCB", NULL, "ADCB Swap Mux"},
{"ADCA", NULL, "ADCA Swap Mux"},
{"ADCA Swap Mux", NULL, "ADCA"},
{"ADCB Swap Mux", NULL, "ADCB"},
{"DACA", "Left", "ADCA Swap Mux"},
{"DACA", "LR 2", "ADCA Swap Mux"},
{"DACA", "Right", "ADCA Swap Mux"},
{"DACB", "Left", "ADCB Swap Mux"},
{"DACB", "LR 2", "ADCB Swap Mux"},
{"DACB", "Right", "ADCB Swap Mux"},
{"ADCA Mux", NULL, "AIN3A"},
{"ADCA Mux", NULL, "AIN2A"},
......@@ -633,30 +657,32 @@ static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
{"PGAB Input Mux", NULL, "AIN2B"},
{"PGAB Input Mux", NULL, "AIN3B"},
{"LOB", NULL, "Lineout Right"},
{"LOA", NULL, "Lineout Left"},
{"Lineout Right", "Switch", "LINEOUTB Input Mux"},
{"Lineout Left", "Switch", "LINEOUTA Input Mux"},
{"LOB", "Switch", "LINEOUTB Input Mux"},
{"LOA", "Switch", "LINEOUTA Input Mux"},
{"LINEOUTA Input Mux", "PGAA", "PGAA"},
{"LINEOUTB Input Mux", "PGAB", "PGAB"},
{"LINEOUTA Input Mux", "DACA", "DACA"},
{"LINEOUTB Input Mux", "DACB", "DACB"},
{"HPA", NULL, "Headphone Left"},
{"HPB", NULL, "Headphone Right"},
{"Headphone Right", "Switch", "HPB Input Mux"},
{"Headphone Left", "Switch", "HPA Input Mux"},
{"HPA", "Switch", "HPB Input Mux"},
{"HPB", "Switch", "HPA Input Mux"},
{"HPA Input Mux", "PGAA", "PGAA"},
{"HPB Input Mux", "PGAB", "PGAB"},
{"HPA Input Mux", "DACA", "DACA"},
{"HPB Input Mux", "DACB", "DACB"},
{"DACB", NULL, "HiFi Playback"},
{"DACA", NULL, "HiFi Playback"},
{"DACA", NULL, "PCMA Swap Mux"},
{"DACB", NULL, "PCMB Swap Mux"},
{"PCMB Swap Mux", "Left", "HiFi Playback"},
{"PCMB Swap Mux", "LR 2", "HiFi Playback"},
{"PCMB Swap Mux", "Right", "HiFi Playback"},
{"PCMA Swap Mux", "Left", "HiFi Playback"},
{"PCMA Swap Mux", "LR 2", "HiFi Playback"},
{"PCMA Swap Mux", "Right", "HiFi Playback"},
};
......
......@@ -219,6 +219,9 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_RIGHT_J:
val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
break;
case SND_SOC_DAIFMT_DSP_A:
val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
break;
default:
dev_err(codec->dev, "unsupported dai format\n");
return -EINVAL;
......@@ -422,7 +425,7 @@ const struct cs42xx8_driver_data cs42888_data = {
};
EXPORT_SYMBOL_GPL(cs42888_data);
const struct of_device_id cs42xx8_of_match[] = {
static const struct of_device_id cs42xx8_of_match[] = {
{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
{ /* sentinel */ }
......
......@@ -128,8 +128,8 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap);
#define CS42XX8_INTF_DAC_DIF_RIGHTJ (2 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_DAC_DIF_ONELINE_20 (4 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (6 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_DAC_DIF_TDM (7 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_DAC_DIF_ONELINE_24 (5 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_DAC_DIF_TDM (6 << CS42XX8_INTF_DAC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_SHIFT 0
#define CS42XX8_INTF_ADC_DIF_WIDTH 3
#define CS42XX8_INTF_ADC_DIF_MASK (((1 << CS42XX8_INTF_ADC_DIF_WIDTH) - 1) << CS42XX8_INTF_ADC_DIF_SHIFT)
......@@ -138,8 +138,8 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap);
#define CS42XX8_INTF_ADC_DIF_RIGHTJ (2 << CS42XX8_INTF_ADC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42XX8_INTF_ADC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_ONELINE_20 (4 << CS42XX8_INTF_ADC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (6 << CS42XX8_INTF_ADC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_TDM (7 << CS42XX8_INTF_ADC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_ONELINE_24 (5 << CS42XX8_INTF_ADC_DIF_SHIFT)
#define CS42XX8_INTF_ADC_DIF_TDM (6 << CS42XX8_INTF_ADC_DIF_SHIFT)
/* ADC Control & DAC De-Emphasis (Address 05h) */
#define CS42XX8_ADCCTL_ADC_HPF_FREEZE_SHIFT 7
......
......@@ -383,8 +383,8 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
if (cx20442->control_data) {
struct tty_struct *tty = cx20442->control_data;
tty_hangup(tty);
struct tty_struct *tty = cx20442->control_data;
tty_hangup(tty);
}
if (!IS_ERR(cx20442->por)) {
......
config SND_DAVINCI_SOC
tristate "SoC Audio for TI DAVINCI or AM33XX/AM43XX chips"
depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX
tristate "SoC Audio for TI DAVINCI"
depends on ARCH_DAVINCI
config SND_EDMA_SOC
tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)"
depends on SOC_AM33XX || SOC_AM43XX
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M here if you want audio support for TI SoC which uses eDMA.
The following line of SoCs are supported by this platform driver:
- AM335x
- AM437x/AM438x
config SND_DAVINCI_SOC_I2S
tristate
config SND_DAVINCI_SOC_MCASP
depends on SND_DAVINCI_SOC || SND_OMAP_SOC
tristate
tristate "Multichannel Audio Serial Port (McASP) support"
depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC
help
Say Y or M here if you want to have support for McASP IP found in
various Texas Instruments SoCs like:
- daVinci devices
- Sitara line of SoCs (AM335x, AM438x, etc)
- DRA7x devices
config SND_DAVINCI_SOC_VCIF
tristate
......@@ -19,7 +35,7 @@ config SND_DAVINCI_SOC_GENERIC_EVM
config SND_AM33XX_SOC_EVM
tristate "SoC Audio for the AM33XX chip based boards"
depends on SND_DAVINCI_SOC && SOC_AM33XX && I2C
depends on SND_EDMA_SOC && SOC_AM33XX && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y or M if you want to add support for SoC audio on AM33XX
......
# DAVINCI Platform Support
snd-soc-davinci-objs := davinci-pcm.o
snd-soc-edma-objs := edma-pcm.o
snd-soc-davinci-i2s-objs := davinci-i2s.o
snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
snd-soc-davinci-vcif-objs:= davinci-vcif.o
obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
......
......@@ -27,6 +27,7 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <sound/asoundef.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
......@@ -36,6 +37,7 @@
#include <sound/omap-pcm.h>
#include "davinci-pcm.h"
#include "edma-pcm.h"
#include "davinci-mcasp.h"
#define MCASP_MAX_AFIFO_DEPTH 64
......@@ -63,6 +65,7 @@ struct davinci_mcasp {
u8 num_serializer;
u8 *serial_dir;
u8 version;
u8 bclk_div;
u16 bclk_lrclk_ratio;
int streams;
......@@ -417,6 +420,7 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
ACLKXDIV(div - 1), ACLKXDIV_MASK);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
ACLKRDIV(div - 1), ACLKRDIV_MASK);
mcasp->bclk_div = div;
break;
case 2: /* BCLK/LRCLK ratio */
......@@ -637,8 +641,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
}
/* S/PDIF */
static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
unsigned int rate)
{
u32 cs_value = 0;
u8 *cs_bytes = (u8*) &cs_value;
/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
and LSB first */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
......@@ -660,6 +668,46 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
/* Enable the DIT */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
/* Set S/PDIF channel status bits */
cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;
switch (rate) {
case 22050:
cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
break;
case 24000:
cs_bytes[3] |= IEC958_AES3_CON_FS_24000;
break;
case 32000:
cs_bytes[3] |= IEC958_AES3_CON_FS_32000;
break;
case 44100:
cs_bytes[3] |= IEC958_AES3_CON_FS_44100;
break;
case 48000:
cs_bytes[3] |= IEC958_AES3_CON_FS_48000;
break;
case 88200:
cs_bytes[3] |= IEC958_AES3_CON_FS_88200;
break;
case 96000:
cs_bytes[3] |= IEC958_AES3_CON_FS_96000;
break;
case 176400:
cs_bytes[3] |= IEC958_AES3_CON_FS_176400;
break;
case 192000:
cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
break;
default:
printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
return -EINVAL;
}
mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
return 0;
}
......@@ -675,15 +723,22 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
int period_size = params_period_size(params);
int ret;
/* If mcasp is BCLK master we need to set BCLK divider */
if (mcasp->bclk_master) {
/*
* If mcasp is BCLK master, and a BCLK divider was not provided by
* the machine driver, we need to calculate the ratio.
*/
if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
unsigned int bclk_freq = snd_soc_params_to_bclk(params);
unsigned int div = mcasp->sysclk_freq / bclk_freq;
if (mcasp->sysclk_freq % bclk_freq != 0) {
dev_err(mcasp->dev, "Can't produce required BCLK\n");
return -EINVAL;
if (((mcasp->sysclk_freq / div) - bclk_freq) >
(bclk_freq - (mcasp->sysclk_freq / (div+1))))
div++;
dev_warn(mcasp->dev,
"Inaccurate BCLK: %u Hz / %u != %u Hz\n",
mcasp->sysclk_freq, div, bclk_freq);
}
davinci_mcasp_set_clkdiv(
cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
davinci_mcasp_set_clkdiv(cpu_dai, 1, div);
}
ret = mcasp_common_hw_param(mcasp, substream->stream,
......@@ -692,7 +747,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return ret;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
ret = mcasp_dit_hw_param(mcasp);
ret = mcasp_dit_hw_param(mcasp, params_rate(params));
else
ret = mcasp_i2s_hw_param(mcasp, substream->stream);
......@@ -782,7 +837,7 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
if (mcasp->version == MCASP_VERSION_4) {
if (mcasp->version >= MCASP_VERSION_3) {
/* Using dmaengine PCM */
dai->playback_dma_data =
&mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
......@@ -1232,10 +1287,16 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
IS_MODULE(CONFIG_SND_DAVINCI_SOC))
case MCASP_VERSION_1:
case MCASP_VERSION_2:
case MCASP_VERSION_3:
ret = davinci_soc_platform_register(&pdev->dev);
break;
#endif
#if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
(IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
IS_MODULE(CONFIG_SND_EDMA_SOC))
case MCASP_VERSION_3:
ret = edma_pcm_platform_register(&pdev->dev);
break;
#endif
#if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \
(IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
IS_MODULE(CONFIG_SND_OMAP_SOC))
......
......@@ -28,8 +28,8 @@
static const struct snd_pcm_hardware edma_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
SNDRV_PCM_INFO_INTERLEAVED,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
......
......@@ -20,6 +20,13 @@
#ifndef __EDMA_PCM_H__
#define __EDMA_PCM_H__
#if IS_ENABLED(CONFIG_SND_EDMA_SOC)
int edma_pcm_platform_register(struct device *dev);
#else
static inline int edma_pcm_platform_register(struct device *dev)
{
return 0;
}
#endif /* CONFIG_SND_EDMA_SOC */
#endif /* __EDMA_PCM_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册