Merge remote-tracking branches 'asoc/topic/twl4030', 'asoc/topic/twl6040', 'asoc/topic/uda134x', 'asoc/topic/uda1380' and 'asoc/topic/uniphier' into asoc-next
This commit is contained in:
Коммит
7fa89d6132
|
@ -0,0 +1,45 @@
|
|||
Socionext UniPhier SoC audio driver
|
||||
|
||||
The Socionext UniPhier audio subsystem consists of I2S and S/PDIF blocks in
|
||||
the same register space.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of the following:
|
||||
"socionext,uniphier-ld11-aio"
|
||||
"socionext,uniphier-ld20-aio"
|
||||
"socionext,uniphier-pxs2-aio"
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain I2S or S/PDIF interrupt.
|
||||
- pinctrl-names : should be "default".
|
||||
- pinctrl-0 : defined I2S signal pins for an external codec chip.
|
||||
- clock-names : should include following entries:
|
||||
"aio"
|
||||
- clocks : a list of phandle, should contain an entry for each
|
||||
entry in clock-names.
|
||||
- reset-names : should include following entries:
|
||||
"aio"
|
||||
- resets : a list of phandle, should contain an entry for each
|
||||
entry in reset-names.
|
||||
- #sound-dai-cells: should be 1.
|
||||
|
||||
Optional properties:
|
||||
- socionext,syscon: a phandle, should contain soc-glue.
|
||||
The soc-glue is used for changing mode of S/PDIF signal pin
|
||||
to Output from Hi-Z. This property is optional if you use
|
||||
I2S signal pins only.
|
||||
|
||||
Example:
|
||||
audio {
|
||||
compatible = "socionext,uniphier-ld20-aio";
|
||||
reg = <0x56000000 0x80000>;
|
||||
interrupts = <0 144 4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_aout>;
|
||||
clock-names = "aio";
|
||||
clocks = <&sys_clk 40>;
|
||||
reset-names = "aio";
|
||||
resets = <&sys_rst 40>;
|
||||
#sound-dai-cells = <1>;
|
||||
|
||||
socionext,syscon = <&sg>;
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -76,7 +76,7 @@ struct twl6040_data {
|
|||
unsigned int clk_in;
|
||||
unsigned int sysclk;
|
||||
struct twl6040_jack_data hs_jack;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_component *component;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
|
@ -106,12 +106,12 @@ static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
|
|||
{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
|
||||
};
|
||||
|
||||
#define to_twl6040(codec) dev_get_drvdata((codec)->dev->parent)
|
||||
#define to_twl6040(component) dev_get_drvdata((component)->dev->parent)
|
||||
|
||||
static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
|
||||
static unsigned int twl6040_read(struct snd_soc_component *component, unsigned int reg)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
struct twl6040 *twl6040 = to_twl6040(component);
|
||||
u8 value;
|
||||
|
||||
if (reg >= TWL6040_CACHEREGNUM)
|
||||
|
@ -133,10 +133,10 @@ static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
|
|||
return value;
|
||||
}
|
||||
|
||||
static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
|
||||
static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (reg) {
|
||||
case TWL6040_REG_HSLCTL:
|
||||
|
@ -152,10 +152,10 @@ static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
|
||||
static inline void twl6040_update_dl12_cache(struct snd_soc_component *component,
|
||||
u8 reg, u8 value)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (reg) {
|
||||
case TWL6040_REG_HSLCTL:
|
||||
|
@ -170,54 +170,54 @@ static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static int twl6040_write(struct snd_soc_codec *codec,
|
||||
static int twl6040_write(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040 *twl6040 = to_twl6040(component);
|
||||
|
||||
if (reg >= TWL6040_CACHEREGNUM)
|
||||
return -EIO;
|
||||
|
||||
twl6040_update_dl12_cache(codec, reg, value);
|
||||
if (twl6040_can_write_to_chip(codec, reg))
|
||||
twl6040_update_dl12_cache(component, reg, value);
|
||||
if (twl6040_can_write_to_chip(component, reg))
|
||||
return twl6040_reg_write(twl6040, reg, value);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl6040_init_chip(struct snd_soc_codec *codec)
|
||||
static void twl6040_init_chip(struct snd_soc_component *component)
|
||||
{
|
||||
twl6040_read(codec, TWL6040_REG_TRIM1);
|
||||
twl6040_read(codec, TWL6040_REG_TRIM2);
|
||||
twl6040_read(codec, TWL6040_REG_TRIM3);
|
||||
twl6040_read(codec, TWL6040_REG_HSOTRIM);
|
||||
twl6040_read(codec, TWL6040_REG_HFOTRIM);
|
||||
twl6040_read(component, TWL6040_REG_TRIM1);
|
||||
twl6040_read(component, TWL6040_REG_TRIM2);
|
||||
twl6040_read(component, TWL6040_REG_TRIM3);
|
||||
twl6040_read(component, TWL6040_REG_HSOTRIM);
|
||||
twl6040_read(component, TWL6040_REG_HFOTRIM);
|
||||
|
||||
/* Change chip defaults */
|
||||
/* No imput selected for microphone amplifiers */
|
||||
twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18);
|
||||
twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);
|
||||
twl6040_write(component, TWL6040_REG_MICLCTL, 0x18);
|
||||
twl6040_write(component, TWL6040_REG_MICRCTL, 0x18);
|
||||
|
||||
/*
|
||||
* We need to lower the default gain values, so the ramp code
|
||||
* can work correctly for the first playback.
|
||||
* This reduces the pop noise heard at the first playback.
|
||||
*/
|
||||
twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff);
|
||||
twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e);
|
||||
twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d);
|
||||
twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d);
|
||||
twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);
|
||||
twl6040_write(component, TWL6040_REG_HSGAIN, 0xff);
|
||||
twl6040_write(component, TWL6040_REG_EARCTL, 0x1e);
|
||||
twl6040_write(component, TWL6040_REG_HFLGAIN, 0x1d);
|
||||
twl6040_write(component, TWL6040_REG_HFRGAIN, 0x1d);
|
||||
twl6040_write(component, TWL6040_REG_LINEGAIN, 0);
|
||||
}
|
||||
|
||||
/* set headset dac and driver power mode */
|
||||
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
|
||||
static int headset_power_mode(struct snd_soc_component *component, int high_perf)
|
||||
{
|
||||
int hslctl, hsrctl;
|
||||
int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
|
||||
|
||||
hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
|
||||
hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
|
||||
hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
|
||||
hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
|
||||
|
||||
if (high_perf) {
|
||||
hslctl &= ~mask;
|
||||
|
@ -227,8 +227,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
|
|||
hsrctl |= mask;
|
||||
}
|
||||
|
||||
twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
|
||||
twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
|
||||
twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
|
||||
twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
|
|||
static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
u8 hslctl, hsrctl;
|
||||
|
||||
/*
|
||||
|
@ -244,8 +244,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
|
|||
* Both HS DAC need to be turned on (before the HS driver) and off at
|
||||
* the same time.
|
||||
*/
|
||||
hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
|
||||
hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
|
||||
hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
|
||||
hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
hslctl |= TWL6040_HSDACENA;
|
||||
hsrctl |= TWL6040_HSDACENA;
|
||||
|
@ -253,8 +253,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
|
|||
hslctl &= ~TWL6040_HSDACENA;
|
||||
hsrctl &= ~TWL6040_HSDACENA;
|
||||
}
|
||||
twl6040_write(codec, TWL6040_REG_HSLCTL, hslctl);
|
||||
twl6040_write(codec, TWL6040_REG_HSRCTL, hsrctl);
|
||||
twl6040_write(component, TWL6040_REG_HSLCTL, hslctl);
|
||||
twl6040_write(component, TWL6040_REG_HSRCTL, hsrctl);
|
||||
|
||||
msleep(1);
|
||||
return 0;
|
||||
|
@ -263,17 +263,17 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
|
|||
static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int ret = 0;
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
/* Earphone doesn't support low power mode */
|
||||
priv->hs_power_mode_locked = 1;
|
||||
ret = headset_power_mode(codec, 1);
|
||||
ret = headset_power_mode(component, 1);
|
||||
} else {
|
||||
priv->hs_power_mode_locked = 0;
|
||||
ret = headset_power_mode(codec, priv->hs_power_mode);
|
||||
ret = headset_power_mode(component, priv->hs_power_mode);
|
||||
}
|
||||
|
||||
msleep(1);
|
||||
|
@ -281,16 +281,16 @@ static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
|
||||
static void twl6040_hs_jack_report(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, int report)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int status;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
/* Sync status */
|
||||
status = twl6040_read(codec, TWL6040_REG_STATUS);
|
||||
status = twl6040_read(component, TWL6040_REG_STATUS);
|
||||
if (status & TWL6040_PLUGCOMP)
|
||||
snd_soc_jack_report(jack, report, report);
|
||||
else
|
||||
|
@ -299,16 +299,16 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
|
|||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
|
||||
void twl6040_hs_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, int report)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
|
||||
|
||||
hs_jack->jack = jack;
|
||||
hs_jack->report = report;
|
||||
|
||||
twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
|
||||
twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
|
||||
|
||||
|
@ -316,17 +316,17 @@ static void twl6040_accessory_work(struct work_struct *work)
|
|||
{
|
||||
struct twl6040_data *priv = container_of(work,
|
||||
struct twl6040_data, hs_jack.work.work);
|
||||
struct snd_soc_codec *codec = priv->codec;
|
||||
struct snd_soc_component *component = priv->component;
|
||||
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
|
||||
|
||||
twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
|
||||
twl6040_hs_jack_report(component, hs_jack->jack, hs_jack->report);
|
||||
}
|
||||
|
||||
/* audio interrupt handler */
|
||||
static irqreturn_t twl6040_audio_handler(int irq, void *data)
|
||||
{
|
||||
struct snd_soc_codec *codec = data;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = data;
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&priv->hs_jack.work, msecs_to_jiffies(200));
|
||||
|
@ -337,12 +337,12 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
|
|||
static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
||||
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
unsigned int val;
|
||||
|
||||
/* Do not allow changes while Input/FF efect is running */
|
||||
val = twl6040_read(codec, e->reg);
|
||||
val = twl6040_read(component, e->reg);
|
||||
if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -486,8 +486,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum,
|
|||
static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = priv->hs_power_mode;
|
||||
|
||||
|
@ -497,13 +497,13 @@ static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
|
|||
static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int high_perf = ucontrol->value.enumerated.item[0];
|
||||
int ret = 0;
|
||||
|
||||
if (!priv->hs_power_mode_locked)
|
||||
ret = headset_power_mode(codec, high_perf);
|
||||
ret = headset_power_mode(component, high_perf);
|
||||
|
||||
if (!ret)
|
||||
priv->hs_power_mode = high_perf;
|
||||
|
@ -514,8 +514,8 @@ static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
|
|||
static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = priv->pll_power_mode;
|
||||
|
||||
|
@ -525,17 +525,17 @@ static int twl6040_pll_get_enum(struct snd_kcontrol *kcontrol,
|
|||
static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
priv->pll_power_mode = ucontrol->value.enumerated.item[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
|
||||
int twl6040_get_dl1_gain(struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
|
||||
|
||||
if (snd_soc_dapm_get_pin_status(dapm, "EP"))
|
||||
return -1; /* -1dB */
|
||||
|
@ -543,7 +543,7 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
|
|||
if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
|
||||
snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
|
||||
|
||||
u8 val = twl6040_read(codec, TWL6040_REG_HSLCTL);
|
||||
u8 val = twl6040_read(component, TWL6040_REG_HSLCTL);
|
||||
if (val & TWL6040_HSDACMODE)
|
||||
/* HSDACL in LP mode */
|
||||
return -8; /* -8dB */
|
||||
|
@ -555,26 +555,26 @@ int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain);
|
||||
|
||||
int twl6040_get_clk_id(struct snd_soc_codec *codec)
|
||||
int twl6040_get_clk_id(struct snd_soc_component *component)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
return priv->pll_power_mode;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl6040_get_clk_id);
|
||||
|
||||
int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
|
||||
int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim)
|
||||
{
|
||||
if (unlikely(trim >= TWL6040_TRIM_INVAL))
|
||||
return -EINVAL;
|
||||
|
||||
return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);
|
||||
return twl6040_read(component, TWL6040_REG_TRIM1 + trim);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
|
||||
|
||||
int twl6040_get_hs_step_size(struct snd_soc_codec *codec)
|
||||
int twl6040_get_hs_step_size(struct snd_soc_component *component)
|
||||
{
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040 *twl6040 = to_twl6040(component);
|
||||
|
||||
if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
|
||||
/* For ES under ES_1.3 HS step is 2 mV */
|
||||
|
@ -829,11 +829,11 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
{"VIBRAR", NULL, "Vibra Right Driver"},
|
||||
};
|
||||
|
||||
static int twl6040_set_bias_level(struct snd_soc_codec *codec,
|
||||
static int twl6040_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040 *twl6040 = to_twl6040(component);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int ret = 0;
|
||||
|
||||
switch (level) {
|
||||
|
@ -856,7 +856,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
|
|||
priv->codec_powered = 1;
|
||||
|
||||
/* Set external boost GPO */
|
||||
twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
|
||||
twl6040_write(component, TWL6040_REG_GPOCTL, 0x02);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
if (!priv->codec_powered)
|
||||
|
@ -873,8 +873,8 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
|
|||
static int twl6040_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
|
@ -887,8 +887,8 @@ static int twl6040_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 twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int rate;
|
||||
|
||||
rate = params_rate(params);
|
||||
|
@ -899,7 +899,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
|
|||
case 88200:
|
||||
/* These rates are not supported when HPPLL is in use */
|
||||
if (unlikely(priv->pll == TWL6040_SYSCLK_SEL_HPPLL)) {
|
||||
dev_err(codec->dev, "HPPLL does not support rate %d\n",
|
||||
dev_err(component->dev, "HPPLL does not support rate %d\n",
|
||||
rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -913,7 +913,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
|
|||
priv->sysclk = 19200000;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unsupported rate %d\n", rate);
|
||||
dev_err(component->dev, "unsupported rate %d\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -923,20 +923,20 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
|
|||
static int twl6040_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct twl6040 *twl6040 = to_twl6040(component);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
if (!priv->sysclk) {
|
||||
dev_err(codec->dev,
|
||||
dev_err(component->dev,
|
||||
"no mclk configured, call set_sysclk() on init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, priv->sysclk);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Can not set PLL (%d)\n", ret);
|
||||
dev_err(component->dev, "Can not set PLL (%d)\n", ret);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
@ -946,8 +946,8 @@ static int twl6040_prepare(struct snd_pcm_substream *substream,
|
|||
static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (clk_id) {
|
||||
case TWL6040_SYSCLK_SEL_LPPLL:
|
||||
|
@ -956,26 +956,26 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
priv->clk_in = freq;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "unknown clk_id %d\n", clk_id);
|
||||
dev_err(component->dev, "unknown clk_id %d\n", clk_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
|
||||
static void twl6040_mute_path(struct snd_soc_component *component, enum twl6040_dai_id id,
|
||||
int mute)
|
||||
{
|
||||
struct twl6040 *twl6040 = to_twl6040(codec);
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040 *twl6040 = to_twl6040(component);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
int hslctl, hsrctl, earctl;
|
||||
int hflctl, hfrctl;
|
||||
|
||||
switch (id) {
|
||||
case TWL6040_DAI_DL1:
|
||||
hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
|
||||
hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
|
||||
earctl = twl6040_read(codec, TWL6040_REG_EARCTL);
|
||||
hslctl = twl6040_read(component, TWL6040_REG_HSLCTL);
|
||||
hsrctl = twl6040_read(component, TWL6040_REG_HSRCTL);
|
||||
earctl = twl6040_read(component, TWL6040_REG_EARCTL);
|
||||
|
||||
if (mute) {
|
||||
/* Power down drivers and DACs */
|
||||
|
@ -991,8 +991,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
|
|||
priv->dl1_unmuted = !mute;
|
||||
break;
|
||||
case TWL6040_DAI_DL2:
|
||||
hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL);
|
||||
hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);
|
||||
hflctl = twl6040_read(component, TWL6040_REG_HFLCTL);
|
||||
hfrctl = twl6040_read(component, TWL6040_REG_HFRCTL);
|
||||
|
||||
if (mute) {
|
||||
/* Power down drivers and DACs */
|
||||
|
@ -1015,12 +1015,12 @@ static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
|
|||
{
|
||||
switch (dai->id) {
|
||||
case TWL6040_DAI_LEGACY:
|
||||
twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute);
|
||||
twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute);
|
||||
twl6040_mute_path(dai->component, TWL6040_DAI_DL1, mute);
|
||||
twl6040_mute_path(dai->component, TWL6040_DAI_DL2, mute);
|
||||
break;
|
||||
case TWL6040_DAI_DL1:
|
||||
case TWL6040_DAI_DL2:
|
||||
twl6040_mute_path(dai->codec, dai->id, mute);
|
||||
twl6040_mute_path(dai->component, dai->id, mute);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1107,23 +1107,23 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int twl6040_probe(struct snd_soc_codec *codec)
|
||||
static int twl6040_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct twl6040_data *priv;
|
||||
struct platform_device *pdev = to_platform_device(codec->dev);
|
||||
struct platform_device *pdev = to_platform_device(component->dev);
|
||||
int ret = 0;
|
||||
|
||||
priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv = devm_kzalloc(component->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
snd_soc_component_set_drvdata(component, priv);
|
||||
|
||||
priv->codec = codec;
|
||||
priv->component = component;
|
||||
|
||||
priv->plug_irq = platform_get_irq(pdev, 0);
|
||||
if (priv->plug_irq < 0) {
|
||||
dev_err(codec->dev, "invalid irq: %d\n", priv->plug_irq);
|
||||
dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq);
|
||||
return priv->plug_irq;
|
||||
}
|
||||
|
||||
|
@ -1134,64 +1134,55 @@ static int twl6040_probe(struct snd_soc_codec *codec)
|
|||
ret = request_threaded_irq(priv->plug_irq, NULL,
|
||||
twl6040_audio_handler,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
"twl6040_irq_plug", codec);
|
||||
"twl6040_irq_plug", component);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
|
||||
dev_err(component->dev, "PLUG IRQ request failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
twl6040_init_chip(codec);
|
||||
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
|
||||
twl6040_init_chip(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6040_remove(struct snd_soc_codec *codec)
|
||||
static void twl6040_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
|
||||
|
||||
free_irq(priv->plug_irq, codec);
|
||||
|
||||
return 0;
|
||||
free_irq(priv->plug_irq, component);
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
|
||||
.probe = twl6040_probe,
|
||||
.remove = twl6040_remove,
|
||||
.read = twl6040_read,
|
||||
.write = twl6040_write,
|
||||
.set_bias_level = twl6040_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
.ignore_pmdown_time = true,
|
||||
|
||||
.component_driver = {
|
||||
.controls = twl6040_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(twl6040_snd_controls),
|
||||
.dapm_widgets = twl6040_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
|
||||
.dapm_routes = intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(intercon),
|
||||
},
|
||||
static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
|
||||
.probe = twl6040_probe,
|
||||
.remove = twl6040_remove,
|
||||
.read = twl6040_read,
|
||||
.write = twl6040_write,
|
||||
.set_bias_level = twl6040_set_bias_level,
|
||||
.controls = twl6040_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(twl6040_snd_controls),
|
||||
.dapm_widgets = twl6040_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(twl6040_dapm_widgets),
|
||||
.dapm_routes = intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(intercon),
|
||||
.suspend_bias_off = 1,
|
||||
.idle_bias_on = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static int twl6040_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl6040,
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&soc_component_dev_twl6040,
|
||||
twl6040_dai, ARRAY_SIZE(twl6040_dai));
|
||||
}
|
||||
|
||||
static int twl6040_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl6040_codec_driver = {
|
||||
.driver = {
|
||||
.name = "twl6040-codec",
|
||||
},
|
||||
.probe = twl6040_codec_probe,
|
||||
.remove = twl6040_codec_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(twl6040_codec_driver);
|
||||
|
|
|
@ -34,11 +34,11 @@ enum twl6040_trim {
|
|||
#define TWL6040_HSF_TRIM_LEFT(x) (x & 0x0f)
|
||||
#define TWL6040_HSF_TRIM_RIGHT(x) ((x >> 4) & 0x0f)
|
||||
|
||||
int twl6040_get_dl1_gain(struct snd_soc_codec *codec);
|
||||
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
|
||||
int twl6040_get_dl1_gain(struct snd_soc_component *component);
|
||||
void twl6040_hs_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, int report);
|
||||
int twl6040_get_clk_id(struct snd_soc_codec *codec);
|
||||
int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim);
|
||||
int twl6040_get_hs_step_size(struct snd_soc_codec *codec);
|
||||
int twl6040_get_clk_id(struct snd_soc_component *component);
|
||||
int twl6040_get_trim_value(struct snd_soc_component *component, enum twl6040_trim trim);
|
||||
int twl6040_get_hs_step_size(struct snd_soc_component *component);
|
||||
|
||||
#endif /* End of __TWL6040_H__ */
|
||||
|
|
|
@ -110,9 +110,9 @@ static int uda134x_regmap_write(void *context, unsigned int reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void uda134x_reset(struct snd_soc_codec *codec)
|
||||
static inline void uda134x_reset(struct snd_soc_component *component)
|
||||
{
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
unsigned int mask = 1<<6;
|
||||
|
||||
regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
|
||||
|
@ -122,7 +122,7 @@ static inline void uda134x_reset(struct snd_soc_codec *codec)
|
|||
|
||||
static int uda134x_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec);
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
|
||||
unsigned int mask = 1<<2;
|
||||
unsigned int val;
|
||||
|
||||
|
@ -139,8 +139,8 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute)
|
|||
static int uda134x_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
struct snd_pcm_runtime *master_runtime;
|
||||
|
||||
if (uda134x->master_substream) {
|
||||
|
@ -168,8 +168,8 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
|
|||
static void uda134x_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (uda134x->master_substream == substream)
|
||||
uda134x->master_substream = uda134x->slave_substream;
|
||||
|
@ -181,8 +181,8 @@ static int uda134x_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 uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
unsigned int hw_params = 0;
|
||||
|
||||
if (substream == uda134x->slave_substream) {
|
||||
|
@ -248,8 +248,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
|
|||
static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
|
||||
pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
|
||||
clk_id, freq, dir);
|
||||
|
@ -270,8 +270,8 @@ static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
|
||||
pr_debug("%s fmt: %08X\n", __func__, fmt);
|
||||
|
||||
|
@ -294,10 +294,10 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int uda134x_set_bias_level(struct snd_soc_codec *codec,
|
||||
static int uda134x_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
struct uda134x_platform_data *pd = uda134x->pd;
|
||||
pr_debug("%s bias level %d\n", __func__, level);
|
||||
|
||||
|
@ -446,10 +446,10 @@ static struct snd_soc_dai_driver uda134x_dai = {
|
|||
.ops = &uda134x_dai_ops,
|
||||
};
|
||||
|
||||
static int uda134x_soc_probe(struct snd_soc_codec *codec)
|
||||
static int uda134x_soc_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
|
||||
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
|
||||
struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
|
||||
struct uda134x_platform_data *pd = uda134x->pd;
|
||||
const struct snd_soc_dapm_widget *widgets;
|
||||
unsigned num_widgets;
|
||||
|
@ -473,7 +473,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
|
|||
if (pd->power)
|
||||
pd->power(1);
|
||||
|
||||
uda134x_reset(codec);
|
||||
uda134x_reset(component);
|
||||
|
||||
if (pd->model == UDA134X_UDA1341) {
|
||||
widgets = uda1341_dapm_widgets;
|
||||
|
@ -493,15 +493,15 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
|
|||
switch (pd->model) {
|
||||
case UDA134X_UDA1340:
|
||||
case UDA134X_UDA1344:
|
||||
ret = snd_soc_add_codec_controls(codec, uda1340_snd_controls,
|
||||
ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
|
||||
ARRAY_SIZE(uda1340_snd_controls));
|
||||
break;
|
||||
case UDA134X_UDA1341:
|
||||
ret = snd_soc_add_codec_controls(codec, uda1341_snd_controls,
|
||||
ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
|
||||
ARRAY_SIZE(uda1341_snd_controls));
|
||||
break;
|
||||
case UDA134X_UDA1345:
|
||||
ret = snd_soc_add_codec_controls(codec, uda1345_snd_controls,
|
||||
ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
|
||||
ARRAY_SIZE(uda1345_snd_controls));
|
||||
break;
|
||||
default:
|
||||
|
@ -518,17 +518,18 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_uda134x = {
|
||||
.probe = uda134x_soc_probe,
|
||||
.set_bias_level = uda134x_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.component_driver = {
|
||||
.dapm_widgets = uda134x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
|
||||
.dapm_routes = uda134x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
|
||||
},
|
||||
static const struct snd_soc_component_driver soc_component_dev_uda134x = {
|
||||
.probe = uda134x_soc_probe,
|
||||
.set_bias_level = uda134x_set_bias_level,
|
||||
.dapm_widgets = uda134x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
|
||||
.dapm_routes = uda134x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
|
||||
.suspend_bias_off = 1,
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct regmap_config uda134x_regmap_config = {
|
||||
|
@ -571,14 +572,8 @@ static int uda134x_codec_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(uda134x->regmap))
|
||||
return PTR_ERR(uda134x->regmap);
|
||||
|
||||
return snd_soc_register_codec(&pdev->dev,
|
||||
&soc_codec_dev_uda134x, &uda134x_dai, 1);
|
||||
}
|
||||
|
||||
static int uda134x_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
return 0;
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&soc_component_dev_uda134x, &uda134x_dai, 1);
|
||||
}
|
||||
|
||||
static struct platform_driver uda134x_codec_driver = {
|
||||
|
@ -586,7 +581,6 @@ static struct platform_driver uda134x_codec_driver = {
|
|||
.name = "uda134x-codec",
|
||||
},
|
||||
.probe = uda134x_codec_probe,
|
||||
.remove = uda134x_codec_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(uda134x_codec_driver);
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
/* codec private data */
|
||||
struct uda1380_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_component *component;
|
||||
unsigned int dac_clk;
|
||||
struct work_struct work;
|
||||
struct i2c_client *i2c;
|
||||
|
@ -61,10 +61,10 @@ static unsigned long uda1380_cache_dirty;
|
|||
/*
|
||||
* read uda1380 register cache
|
||||
*/
|
||||
static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
|
||||
static inline unsigned int uda1380_read_reg_cache(struct snd_soc_component *component,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
u16 *cache = uda1380->reg_cache;
|
||||
|
||||
if (reg == UDA1380_RESET)
|
||||
|
@ -77,10 +77,10 @@ static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
|
|||
/*
|
||||
* write uda1380 register cache
|
||||
*/
|
||||
static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
|
||||
static inline void uda1380_write_reg_cache(struct snd_soc_component *component,
|
||||
u16 reg, unsigned int value)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
u16 *cache = uda1380->reg_cache;
|
||||
|
||||
if (reg >= UDA1380_CACHEREGNUM)
|
||||
|
@ -93,10 +93,10 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
|
|||
/*
|
||||
* write to the UDA1380 register space
|
||||
*/
|
||||
static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
static int uda1380_write(struct snd_soc_component *component, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
u8 data[3];
|
||||
|
||||
/* data is
|
||||
|
@ -108,12 +108,12 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
data[1] = (value & 0xff00) >> 8;
|
||||
data[2] = value & 0x00ff;
|
||||
|
||||
uda1380_write_reg_cache(codec, reg, value);
|
||||
uda1380_write_reg_cache(component, reg, value);
|
||||
|
||||
/* the interpolator & decimator regs must only be written when the
|
||||
* codec DAI is active.
|
||||
*/
|
||||
if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
|
||||
if (!snd_soc_component_is_active(component) && (reg >= UDA1380_MVOL))
|
||||
return 0;
|
||||
pr_debug("uda1380: hw write %x val %x\n", reg, value);
|
||||
if (i2c_master_send(uda1380->i2c, data, 3) == 3) {
|
||||
|
@ -133,9 +133,9 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static void uda1380_sync_cache(struct snd_soc_codec *codec)
|
||||
static void uda1380_sync_cache(struct snd_soc_component *component)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
int reg;
|
||||
u8 data[3];
|
||||
u16 *cache = uda1380->reg_cache;
|
||||
|
@ -146,15 +146,15 @@ static void uda1380_sync_cache(struct snd_soc_codec *codec)
|
|||
data[1] = (cache[reg] & 0xff00) >> 8;
|
||||
data[2] = cache[reg] & 0x00ff;
|
||||
if (i2c_master_send(uda1380->i2c, data, 3) != 3)
|
||||
dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
|
||||
dev_err(component->dev, "%s: write to reg 0x%x failed\n",
|
||||
__func__, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int uda1380_reset(struct snd_soc_codec *codec)
|
||||
static int uda1380_reset(struct snd_soc_component *component)
|
||||
{
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda1380_platform_data *pdata = component->dev->platform_data;
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_reset)) {
|
||||
gpio_set_value(pdata->gpio_reset, 1);
|
||||
|
@ -168,7 +168,7 @@ static int uda1380_reset(struct snd_soc_codec *codec)
|
|||
data[2] = 0;
|
||||
|
||||
if (i2c_master_send(uda1380->i2c, data, 3) != 3) {
|
||||
dev_err(codec->dev, "%s: failed\n", __func__);
|
||||
dev_err(component->dev, "%s: failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
@ -179,15 +179,15 @@ static int uda1380_reset(struct snd_soc_codec *codec)
|
|||
static void uda1380_flush_work(struct work_struct *work)
|
||||
{
|
||||
struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
|
||||
struct snd_soc_codec *uda1380_codec = uda1380->codec;
|
||||
struct snd_soc_component *uda1380_component = uda1380->component;
|
||||
int bit, reg;
|
||||
|
||||
for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
|
||||
reg = 0x10 + bit;
|
||||
pr_debug("uda1380: flush reg %x val %x:\n", reg,
|
||||
uda1380_read_reg_cache(uda1380_codec, reg));
|
||||
uda1380_write(uda1380_codec, reg,
|
||||
uda1380_read_reg_cache(uda1380_codec, reg));
|
||||
uda1380_read_reg_cache(uda1380_component, reg));
|
||||
uda1380_write(uda1380_component, reg,
|
||||
uda1380_read_reg_cache(uda1380_component, reg));
|
||||
clear_bit(bit, &uda1380_cache_dirty);
|
||||
}
|
||||
|
||||
|
@ -420,11 +420,11 @@ static const struct snd_soc_dapm_route uda1380_dapm_routes[] = {
|
|||
static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int iface;
|
||||
|
||||
/* set up DAI based upon fmt */
|
||||
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
|
||||
iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
|
||||
iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
|
@ -442,7 +442,7 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
|
|||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
|
||||
return -EINVAL;
|
||||
|
||||
uda1380_write_reg_cache(codec, UDA1380_IFACE, iface);
|
||||
uda1380_write_reg_cache(component, UDA1380_IFACE, iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -450,11 +450,11 @@ static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
|
|||
static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int iface;
|
||||
|
||||
/* set up DAI based upon fmt */
|
||||
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
|
||||
iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
|
||||
iface &= ~R01_SFORI_MASK;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
|
@ -472,7 +472,7 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
|
|||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
|
||||
return -EINVAL;
|
||||
|
||||
uda1380_write(codec, UDA1380_IFACE, iface);
|
||||
uda1380_write(component, UDA1380_IFACE, iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -480,11 +480,11 @@ static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
|
|||
static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int iface;
|
||||
|
||||
/* set up DAI based upon fmt */
|
||||
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
|
||||
iface = uda1380_read_reg_cache(component, UDA1380_IFACE);
|
||||
iface &= ~(R01_SIM | R01_SFORO_MASK);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
|
@ -501,7 +501,7 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
|
|||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
|
||||
iface |= R01_SIM;
|
||||
|
||||
uda1380_write(codec, UDA1380_IFACE, iface);
|
||||
uda1380_write(component, UDA1380_IFACE, iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -509,20 +509,20 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
|
|||
static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
int mixer = uda1380_read_reg_cache(component, UDA1380_MIXER);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
uda1380_write_reg_cache(codec, UDA1380_MIXER,
|
||||
uda1380_write_reg_cache(component, UDA1380_MIXER,
|
||||
mixer & ~R14_SILENCE);
|
||||
schedule_work(&uda1380->work);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
uda1380_write_reg_cache(codec, UDA1380_MIXER,
|
||||
uda1380_write_reg_cache(component, UDA1380_MIXER,
|
||||
mixer | R14_SILENCE);
|
||||
schedule_work(&uda1380->work);
|
||||
break;
|
||||
|
@ -534,13 +534,13 @@ static int uda1380_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;
|
||||
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
|
||||
|
||||
/* set WSPLL power and divider if running from this clock */
|
||||
if (clk & R00_DAC_CLK) {
|
||||
int rate = params_rate(params);
|
||||
u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
|
||||
u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
|
||||
clk &= ~0x3; /* clear SEL_LOOP_DIV */
|
||||
switch (rate) {
|
||||
case 6250 ... 12500:
|
||||
|
@ -556,7 +556,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
clk |= 0x3;
|
||||
break;
|
||||
}
|
||||
uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm);
|
||||
uda1380_write(component, UDA1380_PM, R02_PON_PLL | pm);
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
@ -564,20 +564,20 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
else
|
||||
clk |= R00_EN_ADC | R00_EN_DEC;
|
||||
|
||||
uda1380_write(codec, UDA1380_CLK, clk);
|
||||
uda1380_write(component, UDA1380_CLK, clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
|
||||
struct snd_soc_component *component = dai->component;
|
||||
u16 clk = uda1380_read_reg_cache(component, UDA1380_CLK);
|
||||
|
||||
/* shut down WSPLL power if running from this clock */
|
||||
if (clk & R00_DAC_CLK) {
|
||||
u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
|
||||
uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm);
|
||||
u16 pm = uda1380_read_reg_cache(component, UDA1380_PM);
|
||||
uda1380_write(component, UDA1380_PM, ~R02_PON_PLL & pm);
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
|
@ -585,33 +585,33 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
|
|||
else
|
||||
clk &= ~(R00_EN_ADC | R00_EN_DEC);
|
||||
|
||||
uda1380_write(codec, UDA1380_CLK, clk);
|
||||
uda1380_write(component, UDA1380_CLK, clk);
|
||||
}
|
||||
|
||||
static int uda1380_set_bias_level(struct snd_soc_codec *codec,
|
||||
static int uda1380_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
|
||||
int pm = uda1380_read_reg_cache(component, UDA1380_PM);
|
||||
int reg;
|
||||
struct uda1380_platform_data *pdata = codec->dev->platform_data;
|
||||
struct uda1380_platform_data *pdata = component->dev->platform_data;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/* ADC, DAC on */
|
||||
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
|
||||
uda1380_write(component, UDA1380_PM, R02_PON_BIAS | pm);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
|
||||
if (gpio_is_valid(pdata->gpio_power)) {
|
||||
gpio_set_value(pdata->gpio_power, 1);
|
||||
mdelay(1);
|
||||
uda1380_reset(codec);
|
||||
uda1380_reset(component);
|
||||
}
|
||||
|
||||
uda1380_sync_cache(codec);
|
||||
uda1380_sync_cache(component);
|
||||
}
|
||||
uda1380_write(codec, UDA1380_PM, 0x0);
|
||||
uda1380_write(component, UDA1380_PM, 0x0);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
if (!gpio_is_valid(pdata->gpio_power))
|
||||
|
@ -694,16 +694,16 @@ static struct snd_soc_dai_driver uda1380_dai[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int uda1380_probe(struct snd_soc_codec *codec)
|
||||
static int uda1380_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct uda1380_platform_data *pdata =codec->dev->platform_data;
|
||||
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
|
||||
struct uda1380_platform_data *pdata =component->dev->platform_data;
|
||||
struct uda1380_priv *uda1380 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
uda1380->codec = codec;
|
||||
uda1380->component = component;
|
||||
|
||||
if (!gpio_is_valid(pdata->gpio_power)) {
|
||||
ret = uda1380_reset(codec);
|
||||
ret = uda1380_reset(component);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -713,10 +713,10 @@ static int uda1380_probe(struct snd_soc_codec *codec)
|
|||
/* set clock input */
|
||||
switch (pdata->dac_clk) {
|
||||
case UDA1380_DAC_CLK_SYSCLK:
|
||||
uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
|
||||
uda1380_write_reg_cache(component, UDA1380_CLK, 0);
|
||||
break;
|
||||
case UDA1380_DAC_CLK_WSPLL:
|
||||
uda1380_write_reg_cache(codec, UDA1380_CLK,
|
||||
uda1380_write_reg_cache(component, UDA1380_CLK,
|
||||
R00_DAC_CLK);
|
||||
break;
|
||||
}
|
||||
|
@ -724,21 +724,22 @@ static int uda1380_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
|
||||
.probe = uda1380_probe,
|
||||
.read = uda1380_read_reg_cache,
|
||||
.write = uda1380_write,
|
||||
.set_bias_level = uda1380_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.component_driver = {
|
||||
.controls = uda1380_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(uda1380_snd_controls),
|
||||
.dapm_widgets = uda1380_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
|
||||
.dapm_routes = uda1380_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
|
||||
},
|
||||
static const struct snd_soc_component_driver soc_component_dev_uda1380 = {
|
||||
.probe = uda1380_probe,
|
||||
.read = uda1380_read_reg_cache,
|
||||
.write = uda1380_write,
|
||||
.set_bias_level = uda1380_set_bias_level,
|
||||
.controls = uda1380_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(uda1380_snd_controls),
|
||||
.dapm_widgets = uda1380_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
|
||||
.dapm_routes = uda1380_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
|
||||
.suspend_bias_off = 1,
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static int uda1380_i2c_probe(struct i2c_client *i2c,
|
||||
|
@ -780,17 +781,11 @@ static int uda1380_i2c_probe(struct i2c_client *i2c,
|
|||
i2c_set_clientdata(i2c, uda1380);
|
||||
uda1380->i2c = i2c;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
|
||||
ret = devm_snd_soc_register_component(&i2c->dev,
|
||||
&soc_component_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uda1380_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id uda1380_i2c_id[] = {
|
||||
{ "uda1380", 0 },
|
||||
{ }
|
||||
|
@ -809,7 +804,6 @@ static struct i2c_driver uda1380_i2c_driver = {
|
|||
.of_match_table = uda1380_of_match,
|
||||
},
|
||||
.probe = uda1380_i2c_probe,
|
||||
.remove = uda1380_i2c_remove,
|
||||
.id_table = uda1380_i2c_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ static int omap_abe_hw_params(struct snd_pcm_substream *substream,
|
|||
int clk_id, freq;
|
||||
int ret;
|
||||
|
||||
clk_id = twl6040_get_clk_id(rtd->codec);
|
||||
clk_id = twl6040_get_clk_id(codec_dai->component);
|
||||
if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
|
||||
freq = priv->mclk_freq;
|
||||
else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
|
||||
|
@ -166,7 +166,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|||
|
||||
static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
|
||||
int hs_trim;
|
||||
|
@ -176,7 +176,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
|
|||
* Configure McPDM offset cancellation based on the HSOTRIM value from
|
||||
* twl6040.
|
||||
*/
|
||||
hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
|
||||
hs_trim = twl6040_get_trim_value(component, TWL6040_TRIM_HSOTRIM);
|
||||
omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
|
||||
TWL6040_HSF_TRIM_RIGHT(hs_trim));
|
||||
|
||||
|
@ -189,7 +189,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
|
||||
twl6040_hs_jack_detect(component, &hs_jack, SND_JACK_HEADSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -8,6 +8,39 @@ config SND_SOC_UNIPHIER
|
|||
audio interfaces to support below.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_UNIPHIER_AIO
|
||||
tristate "UniPhier AIO DAI Driver"
|
||||
select REGMAP_MMIO
|
||||
select SND_SOC_COMPRESS
|
||||
depends on SND_SOC_UNIPHIER
|
||||
help
|
||||
This adds ASoC driver support for Socionext UniPhier
|
||||
'AIO' Audio Input/Output subsystem.
|
||||
Select Y if you use such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_UNIPHIER_LD11
|
||||
tristate "UniPhier LD11/LD20 Device Driver"
|
||||
depends on SND_SOC_UNIPHIER
|
||||
select SND_SOC_UNIPHIER_AIO
|
||||
select SND_SOC_UNIPHIER_AIO_DMA
|
||||
help
|
||||
This adds ASoC driver for Socionext UniPhier LD11/LD20
|
||||
input and output that can be used with other codecs.
|
||||
Select Y if you use such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_UNIPHIER_PXS2
|
||||
tristate "UniPhier PXs2 Device Driver"
|
||||
depends on SND_SOC_UNIPHIER
|
||||
select SND_SOC_UNIPHIER_AIO
|
||||
select SND_SOC_UNIPHIER_AIO_DMA
|
||||
help
|
||||
This adds ASoC driver for Socionext UniPhier PXs2
|
||||
input and output that can be used with other codecs.
|
||||
Select Y if you use such device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_UNIPHIER_EVEA_CODEC
|
||||
tristate "UniPhier SoC internal audio codec"
|
||||
depends on SND_SOC_UNIPHIER
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
snd-soc-uniphier-aio-cpu-objs := aio-core.o aio-dma.o aio-cpu.o aio-compress.o
|
||||
snd-soc-uniphier-aio-ld11-objs := aio-ld11.o
|
||||
snd-soc-uniphier-aio-pxs2-objs := aio-pxs2.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_UNIPHIER_AIO) += snd-soc-uniphier-aio-cpu.o
|
||||
obj-$(CONFIG_SND_SOC_UNIPHIER_LD11) += snd-soc-uniphier-aio-ld11.o
|
||||
obj-$(CONFIG_SND_SOC_UNIPHIER_PXS2) += snd-soc-uniphier-aio-pxs2.o
|
||||
|
||||
snd-soc-uniphier-evea-objs := evea.o
|
||||
obj-$(CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC) += snd-soc-uniphier-evea.o
|
||||
|
|
|
@ -0,0 +1,438 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Socionext UniPhier AIO Compress Audio driver.
|
||||
//
|
||||
// Copyright (c) 2017-2018 Socionext Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; version 2
|
||||
// of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "aio.h"
|
||||
|
||||
static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream);
|
||||
static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream);
|
||||
|
||||
static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_compr *compr = rtd->compr;
|
||||
struct device *dev = compr->card->dev;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
|
||||
size_t size = AUD_RING_SIZE;
|
||||
int dma_dir = DMA_FROM_DEVICE, ret;
|
||||
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sub->compr_area = kzalloc(size, GFP_KERNEL);
|
||||
if (!sub->compr_area)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sub->swm->dir == PORT_DIR_OUTPUT)
|
||||
dma_dir = DMA_TO_DEVICE;
|
||||
|
||||
sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir);
|
||||
if (dma_mapping_error(dev, sub->compr_addr)) {
|
||||
kfree(sub->compr_area);
|
||||
sub->compr_area = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sub->compr_bytes = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_compr *compr = rtd->compr;
|
||||
struct device *dev = compr->card->dev;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
|
||||
int dma_dir = DMA_FROM_DEVICE;
|
||||
|
||||
if (sub->swm->dir == PORT_DIR_OUTPUT)
|
||||
dma_dir = DMA_TO_DEVICE;
|
||||
|
||||
dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir);
|
||||
kfree(sub->compr_area);
|
||||
sub->compr_area = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
int ret;
|
||||
|
||||
if (sub->cstream)
|
||||
return -EBUSY;
|
||||
|
||||
sub->cstream = cstream;
|
||||
sub->pass_through = 1;
|
||||
sub->use_mmap = false;
|
||||
|
||||
ret = uniphier_aio_comprdma_new(rtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aio_init(sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
int ret;
|
||||
|
||||
ret = uniphier_aio_compr_hw_free(cstream);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = uniphier_aio_comprdma_free(rtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sub->cstream = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
|
||||
struct snd_codec *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
|
||||
*params = sub->cparams.codec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
|
||||
dev_err(dev, "Codec ID is not supported(%d)\n",
|
||||
params->codec.id);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
|
||||
dev_err(dev, "Codec profile is not supported(%d)\n",
|
||||
params->codec.profile);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* IEC frame type will be changed after received valid data */
|
||||
sub->iec_pc = IEC61937_PC_AAC;
|
||||
|
||||
sub->cparams = *params;
|
||||
sub->setting = 1;
|
||||
|
||||
aio_port_reset(sub);
|
||||
aio_src_reset(sub);
|
||||
|
||||
ret = uniphier_aio_compr_prepare(cstream);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
|
||||
sub->setting = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_compr_runtime *runtime = cstream->runtime;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
int bytes = runtime->fragment_size;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = aiodma_ch_set_param(sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
|
||||
sub->compr_addr + sub->compr_bytes,
|
||||
bytes);
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = aio_oport_set_stream_type(sub, sub->iec_pc);
|
||||
if (ret)
|
||||
return ret;
|
||||
aio_port_set_enable(sub, 1);
|
||||
|
||||
ret = aio_if_set_param(sub, sub->pass_through);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
|
||||
int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_compr_runtime *runtime = cstream->runtime;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
int bytes = runtime->fragment_size, ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
|
||||
aiodma_ch_set_enable(sub, 1);
|
||||
sub->running = 1;
|
||||
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
sub->running = 0;
|
||||
aiodma_ch_set_enable(sub, 0);
|
||||
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "Unknown trigger(%d)\n", cmd);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_pointer(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_compr_runtime *runtime = cstream->runtime;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
int bytes = runtime->fragment_size;
|
||||
unsigned long flags;
|
||||
u32 pos;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
|
||||
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
|
||||
|
||||
if (sub->swm->dir == PORT_DIR_OUTPUT) {
|
||||
pos = sub->rd_offs;
|
||||
/* Size of AIO output format is double of IEC61937 */
|
||||
tstamp->copied_total = sub->rd_total / 2;
|
||||
} else {
|
||||
pos = sub->wr_offs;
|
||||
tstamp->copied_total = sub->rd_total;
|
||||
}
|
||||
tstamp->byte_offset = pos;
|
||||
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
|
||||
char __user *buf, size_t dstsize)
|
||||
{
|
||||
u32 __user *srcbuf = (u32 __user *)buf;
|
||||
u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
|
||||
int src = 0, dst = 0, ret;
|
||||
u32 frm, frm_a, frm_b;
|
||||
|
||||
while (dstsize > 0) {
|
||||
ret = get_user(frm, srcbuf + src);
|
||||
if (ret)
|
||||
return ret;
|
||||
src++;
|
||||
|
||||
frm_a = frm & 0xffff;
|
||||
frm_b = (frm >> 16) & 0xffff;
|
||||
|
||||
if (frm == IEC61937_HEADER_SIGN) {
|
||||
frm_a |= 0x01000000;
|
||||
|
||||
/* Next data is Pc and Pd */
|
||||
sub->iec_header = true;
|
||||
} else {
|
||||
u16 pc = be16_to_cpu((__be16)frm_a);
|
||||
|
||||
if (sub->iec_header && sub->iec_pc != pc) {
|
||||
/* Force overwrite IEC frame type */
|
||||
sub->iec_pc = pc;
|
||||
ret = aio_oport_set_stream_type(sub, pc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
sub->iec_header = false;
|
||||
}
|
||||
dstbuf[dst++] = frm_a;
|
||||
dstbuf[dst++] = frm_b;
|
||||
|
||||
dstsize -= sizeof(u32) * 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
|
||||
char __user *buf, size_t count)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
|
||||
struct snd_compr_runtime *runtime = cstream->runtime;
|
||||
struct device *carddev = rtd->compr->card->dev;
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
|
||||
size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
|
||||
int bytes = runtime->fragment_size;
|
||||
unsigned long flags;
|
||||
size_t s;
|
||||
int ret;
|
||||
|
||||
if (cnt < sizeof(u32))
|
||||
return 0;
|
||||
|
||||
if (sub->swm->dir == PORT_DIR_OUTPUT) {
|
||||
dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
|
||||
|
||||
/* Size of AIO output format is double of IEC61937 */
|
||||
s = cnt * 2;
|
||||
|
||||
dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
|
||||
ret = aio_compr_send_to_hw(sub, buf, s);
|
||||
dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
|
||||
} else {
|
||||
dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
|
||||
|
||||
s = cnt;
|
||||
|
||||
dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
|
||||
ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
|
||||
dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
|
||||
}
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
|
||||
sub->threshold = 2 * bytes;
|
||||
aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
|
||||
|
||||
if (sub->swm->dir == PORT_DIR_OUTPUT) {
|
||||
sub->wr_offs += s;
|
||||
if (sub->wr_offs >= sub->compr_bytes)
|
||||
sub->wr_offs -= sub->compr_bytes;
|
||||
} else {
|
||||
sub->rd_offs += s;
|
||||
if (sub->rd_offs >= sub->compr_bytes)
|
||||
sub->rd_offs -= sub->compr_bytes;
|
||||
}
|
||||
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
|
||||
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int uniphier_aio_compr_get_caps(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_caps *caps)
|
||||
{
|
||||
caps->num_codecs = 1;
|
||||
caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
|
||||
caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
|
||||
caps->min_fragments = AUD_MIN_FRAGMENT;
|
||||
caps->max_fragments = AUD_MAX_FRAGMENT;
|
||||
caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_compr_codec_caps caps_iec = {
|
||||
.num_descriptors = 1,
|
||||
.descriptor[0].max_ch = 8,
|
||||
.descriptor[0].num_sample_rates = 0,
|
||||
.descriptor[0].num_bitrates = 0,
|
||||
.descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
|
||||
.descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
|
||||
SND_AUDIOMODE_IEC_MPEG1 |
|
||||
SND_AUDIOMODE_IEC_MP3 |
|
||||
SND_AUDIOMODE_IEC_DTS,
|
||||
.descriptor[0].formats = 0,
|
||||
};
|
||||
|
||||
static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
|
||||
struct snd_compr_codec_caps *codec)
|
||||
{
|
||||
if (codec->codec == SND_AUDIOCODEC_IEC61937)
|
||||
*codec = caps_iec;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_compr_ops uniphier_aio_compr_ops = {
|
||||
.open = uniphier_aio_compr_open,
|
||||
.free = uniphier_aio_compr_free,
|
||||
.get_params = uniphier_aio_compr_get_params,
|
||||
.set_params = uniphier_aio_compr_set_params,
|
||||
.trigger = uniphier_aio_compr_trigger,
|
||||
.pointer = uniphier_aio_compr_pointer,
|
||||
.copy = uniphier_aio_compr_copy,
|
||||
.get_caps = uniphier_aio_compr_get_caps,
|
||||
.get_codec_caps = uniphier_aio_compr_get_codec_caps,
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,578 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Socionext UniPhier AIO ALSA CPU DAI driver.
|
||||
//
|
||||
// Copyright (c) 2016-2018 Socionext Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; version 2
|
||||
// of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "aio.h"
|
||||
|
||||
static bool is_valid_pll(struct uniphier_aio_chip *chip, int pll_id)
|
||||
{
|
||||
struct device *dev = &chip->pdev->dev;
|
||||
|
||||
if (pll_id < 0 || chip->num_plls <= pll_id) {
|
||||
dev_err(dev, "PLL(%d) is not supported\n", pll_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return chip->plls[pll_id].enable;
|
||||
}
|
||||
|
||||
static bool match_spec(const struct uniphier_aio_spec *spec,
|
||||
const char *name, int dir)
|
||||
{
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
spec->swm.dir != PORT_DIR_OUTPUT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dir == SNDRV_PCM_STREAM_CAPTURE &&
|
||||
spec->swm.dir != PORT_DIR_INPUT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spec->name && strcmp(spec->name, name) == 0)
|
||||
return true;
|
||||
|
||||
if (spec->gname && strcmp(spec->gname, name) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_spec - find HW specification info by name
|
||||
* @aio: the AIO device pointer
|
||||
* @name: name of device
|
||||
* @direction: the direction of substream, SNDRV_PCM_STREAM_*
|
||||
*
|
||||
* Find hardware specification information from list by device name. This
|
||||
* information is used for telling the difference of SoCs to driver.
|
||||
*
|
||||
* Specification list is array of 'struct uniphier_aio_spec' which is defined
|
||||
* in each drivers (see: aio-i2s.c).
|
||||
*
|
||||
* Return: The pointer of hardware specification of AIO if successful,
|
||||
* otherwise NULL on error.
|
||||
*/
|
||||
static const struct uniphier_aio_spec *find_spec(struct uniphier_aio *aio,
|
||||
const char *name,
|
||||
int direction)
|
||||
{
|
||||
const struct uniphier_aio_chip_spec *chip_spec = aio->chip->chip_spec;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < chip_spec->num_specs; i++) {
|
||||
const struct uniphier_aio_spec *spec = &chip_spec->specs[i];
|
||||
|
||||
if (match_spec(spec, name, direction))
|
||||
return spec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_divider - find clock divider by frequency
|
||||
* @aio: the AIO device pointer
|
||||
* @pll_id: PLL ID, should be AUD_PLL_XX
|
||||
* @freq: required frequency
|
||||
*
|
||||
* Find suitable clock divider by frequency.
|
||||
*
|
||||
* Return: The ID of PLL if successful, otherwise negative error value.
|
||||
*/
|
||||
static int find_divider(struct uniphier_aio *aio, int pll_id, unsigned int freq)
|
||||
{
|
||||
struct uniphier_aio_pll *pll;
|
||||
int mul[] = { 1, 1, 1, 2, };
|
||||
int div[] = { 2, 3, 1, 3, };
|
||||
int i;
|
||||
|
||||
if (!is_valid_pll(aio->chip, pll_id))
|
||||
return -EINVAL;
|
||||
|
||||
pll = &aio->chip->plls[pll_id];
|
||||
for (i = 0; i < ARRAY_SIZE(mul); i++)
|
||||
if (pll->freq * mul[i] / div[i] == freq)
|
||||
return i;
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int uniphier_aio_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
bool pll_auto = false;
|
||||
int pll_id, div_id;
|
||||
|
||||
switch (clk_id) {
|
||||
case AUD_CLK_IO:
|
||||
return -ENOTSUPP;
|
||||
case AUD_CLK_A1:
|
||||
pll_id = AUD_PLL_A1;
|
||||
break;
|
||||
case AUD_CLK_F1:
|
||||
pll_id = AUD_PLL_F1;
|
||||
break;
|
||||
case AUD_CLK_A2:
|
||||
pll_id = AUD_PLL_A2;
|
||||
break;
|
||||
case AUD_CLK_F2:
|
||||
pll_id = AUD_PLL_F2;
|
||||
break;
|
||||
case AUD_CLK_A:
|
||||
pll_id = AUD_PLL_A1;
|
||||
pll_auto = true;
|
||||
break;
|
||||
case AUD_CLK_F:
|
||||
pll_id = AUD_PLL_F1;
|
||||
pll_auto = true;
|
||||
break;
|
||||
case AUD_CLK_APLL:
|
||||
pll_id = AUD_PLL_APLL;
|
||||
break;
|
||||
case AUD_CLK_RX0:
|
||||
pll_id = AUD_PLL_RX0;
|
||||
break;
|
||||
case AUD_CLK_USB0:
|
||||
pll_id = AUD_PLL_USB0;
|
||||
break;
|
||||
case AUD_CLK_HSC0:
|
||||
pll_id = AUD_PLL_HSC0;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Sysclk(%d) is not supported\n", clk_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pll_auto) {
|
||||
for (pll_id = 0; pll_id < aio->chip->num_plls; pll_id++) {
|
||||
div_id = find_divider(aio, pll_id, freq);
|
||||
if (div_id >= 0) {
|
||||
aio->plldiv = div_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pll_id == aio->chip->num_plls) {
|
||||
dev_err(dev, "Sysclk frequency is not supported(%d)\n",
|
||||
freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == SND_SOC_CLOCK_OUT)
|
||||
aio->pll_out = pll_id;
|
||||
else
|
||||
aio->pll_in = pll_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
|
||||
int source, unsigned int freq_in,
|
||||
unsigned int freq_out)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (!is_valid_pll(aio->chip, pll_id))
|
||||
return -EINVAL;
|
||||
if (!aio->chip->plls[pll_id].enable) {
|
||||
dev_err(dev, "PLL(%d) is not implemented\n", pll_id);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
aio->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Format is not supported(%d)\n",
|
||||
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
int ret;
|
||||
|
||||
sub->substream = substream;
|
||||
sub->pass_through = 0;
|
||||
sub->use_mmap = true;
|
||||
|
||||
ret = aio_init(sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uniphier_aio_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
|
||||
sub->substream = NULL;
|
||||
}
|
||||
|
||||
static int uniphier_aio_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
int freq, ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 32000:
|
||||
case 24000:
|
||||
freq = 12288000;
|
||||
break;
|
||||
case 44100:
|
||||
case 22050:
|
||||
freq = 11289600;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Rate is not supported(%d)\n",
|
||||
params_rate(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = snd_soc_dai_set_sysclk(dai, AUD_CLK_A,
|
||||
freq, SND_SOC_CLOCK_OUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sub->params = *params;
|
||||
sub->setting = 1;
|
||||
|
||||
aio_port_reset(sub);
|
||||
aio_src_reset(sub);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
|
||||
sub->setting = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
int ret;
|
||||
|
||||
ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = aio_src_set_param(sub, &sub->params);
|
||||
if (ret)
|
||||
return ret;
|
||||
aio_port_set_enable(sub, 1);
|
||||
|
||||
ret = aio_if_set_param(sub, sub->pass_through);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sub->swm->type == PORT_TYPE_CONV) {
|
||||
ret = aio_srcif_set_param(sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = aio_srcch_set_param(sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
aio_srcch_set_enable(sub, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
|
||||
.set_sysclk = uniphier_aio_set_sysclk,
|
||||
.set_pll = uniphier_aio_set_pll,
|
||||
.set_fmt = uniphier_aio_set_fmt,
|
||||
.startup = uniphier_aio_startup,
|
||||
.shutdown = uniphier_aio_shutdown,
|
||||
.hw_params = uniphier_aio_hw_params,
|
||||
.hw_free = uniphier_aio_hw_free,
|
||||
.prepare = uniphier_aio_prepare,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
|
||||
|
||||
const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
|
||||
.set_sysclk = uniphier_aio_set_sysclk,
|
||||
.set_pll = uniphier_aio_set_pll,
|
||||
.startup = uniphier_aio_startup,
|
||||
.shutdown = uniphier_aio_shutdown,
|
||||
.hw_params = uniphier_aio_hw_params,
|
||||
.hw_free = uniphier_aio_hw_free,
|
||||
.prepare = uniphier_aio_prepare,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
|
||||
|
||||
int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
|
||||
struct uniphier_aio_sub *sub = &aio->sub[i];
|
||||
const struct uniphier_aio_spec *spec;
|
||||
|
||||
spec = find_spec(aio, dai->name, i);
|
||||
if (!spec)
|
||||
continue;
|
||||
|
||||
sub->swm = &spec->swm;
|
||||
sub->spec = spec;
|
||||
}
|
||||
|
||||
aio_iecout_set_enable(aio->chip, true);
|
||||
aio_chip_init(aio->chip);
|
||||
aio->chip->active = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
|
||||
|
||||
int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
|
||||
aio->chip->active = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
|
||||
|
||||
int uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
|
||||
reset_control_assert(aio->chip->rst);
|
||||
clk_disable_unprepare(aio->chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_dai_suspend);
|
||||
|
||||
int uniphier_aio_dai_resume(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio *aio = uniphier_priv(dai);
|
||||
int ret, i;
|
||||
|
||||
if (!aio->chip->active)
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(aio->chip->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_deassert(aio->chip->rst);
|
||||
if (ret)
|
||||
goto err_out_clock;
|
||||
|
||||
aio_iecout_set_enable(aio->chip, true);
|
||||
aio_chip_init(aio->chip);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aio->sub); i++) {
|
||||
struct uniphier_aio_sub *sub = &aio->sub[i];
|
||||
|
||||
if (!sub->spec || !sub->substream)
|
||||
continue;
|
||||
|
||||
ret = aio_init(sub);
|
||||
if (ret)
|
||||
goto err_out_clock;
|
||||
|
||||
if (!sub->setting)
|
||||
continue;
|
||||
|
||||
aio_port_reset(sub);
|
||||
aio_src_reset(sub);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_clock:
|
||||
clk_disable_unprepare(aio->chip->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_dai_resume);
|
||||
|
||||
static const struct snd_soc_component_driver uniphier_aio_component = {
|
||||
.name = "uniphier-aio",
|
||||
};
|
||||
|
||||
int uniphier_aio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_aio_chip *chip;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret, i, j;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->chip_spec = of_device_get_match_data(dev);
|
||||
if (!chip->chip_spec)
|
||||
return -EINVAL;
|
||||
|
||||
chip->regmap_sg = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"socionext,syscon");
|
||||
if (IS_ERR(chip->regmap_sg)) {
|
||||
if (PTR_ERR(chip->regmap_sg) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
chip->regmap_sg = NULL;
|
||||
}
|
||||
|
||||
chip->clk = devm_clk_get(dev, "aio");
|
||||
if (IS_ERR(chip->clk))
|
||||
return PTR_ERR(chip->clk);
|
||||
|
||||
chip->rst = devm_reset_control_get_shared(dev, "aio");
|
||||
if (IS_ERR(chip->rst))
|
||||
return PTR_ERR(chip->rst);
|
||||
|
||||
chip->num_aios = chip->chip_spec->num_dais;
|
||||
chip->aios = devm_kzalloc(dev,
|
||||
sizeof(struct uniphier_aio) * chip->num_aios,
|
||||
GFP_KERNEL);
|
||||
if (!chip->aios)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->num_plls = chip->chip_spec->num_plls;
|
||||
chip->plls = devm_kzalloc(dev, sizeof(struct uniphier_aio_pll) *
|
||||
chip->num_plls, GFP_KERNEL);
|
||||
if (!chip->plls)
|
||||
return -ENOMEM;
|
||||
memcpy(chip->plls, chip->chip_spec->plls,
|
||||
sizeof(struct uniphier_aio_pll) * chip->num_plls);
|
||||
|
||||
for (i = 0; i < chip->num_aios; i++) {
|
||||
struct uniphier_aio *aio = &chip->aios[i];
|
||||
|
||||
aio->chip = chip;
|
||||
aio->fmt = SND_SOC_DAIFMT_I2S;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
|
||||
struct uniphier_aio_sub *sub = &aio->sub[j];
|
||||
|
||||
sub->aio = aio;
|
||||
spin_lock_init(&sub->lock);
|
||||
}
|
||||
}
|
||||
|
||||
chip->pdev = pdev;
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
ret = clk_prepare_enable(chip->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_deassert(chip->rst);
|
||||
if (ret)
|
||||
goto err_out_clock;
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
|
||||
chip->chip_spec->dais,
|
||||
chip->chip_spec->num_dais);
|
||||
if (ret) {
|
||||
dev_err(dev, "Register component failed.\n");
|
||||
goto err_out_reset;
|
||||
}
|
||||
|
||||
ret = uniphier_aiodma_soc_register_platform(pdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Register platform failed.\n");
|
||||
goto err_out_reset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_reset:
|
||||
reset_control_assert(chip->rst);
|
||||
|
||||
err_out_clock:
|
||||
clk_disable_unprepare(chip->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_probe);
|
||||
|
||||
int uniphier_aio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
reset_control_assert(chip->rst);
|
||||
clk_disable_unprepare(chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aio_remove);
|
||||
|
||||
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier AIO CPU DAI driver.");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,319 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Socionext UniPhier AIO DMA driver.
|
||||
//
|
||||
// Copyright (c) 2016-2018 Socionext Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; version 2
|
||||
// of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "aio.h"
|
||||
|
||||
static struct snd_pcm_hardware uniphier_aiodma_hw = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED,
|
||||
.period_bytes_min = 256,
|
||||
.period_bytes_max = 4096,
|
||||
.periods_min = 4,
|
||||
.periods_max = 1024,
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
};
|
||||
|
||||
static void aiodma_pcm_irq(struct uniphier_aio_sub *sub)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = sub->substream->runtime;
|
||||
int bytes = runtime->period_size *
|
||||
runtime->channels * samples_to_bytes(runtime, 1);
|
||||
int ret;
|
||||
|
||||
spin_lock(&sub->lock);
|
||||
ret = aiodma_rb_set_threshold(sub, runtime->dma_bytes,
|
||||
sub->threshold + bytes);
|
||||
if (!ret)
|
||||
sub->threshold += bytes;
|
||||
|
||||
aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
|
||||
aiodma_rb_clear_irq(sub);
|
||||
spin_unlock(&sub->lock);
|
||||
|
||||
snd_pcm_period_elapsed(sub->substream);
|
||||
}
|
||||
|
||||
static void aiodma_compr_irq(struct uniphier_aio_sub *sub)
|
||||
{
|
||||
struct snd_compr_runtime *runtime = sub->cstream->runtime;
|
||||
int bytes = runtime->fragment_size;
|
||||
int ret;
|
||||
|
||||
spin_lock(&sub->lock);
|
||||
ret = aiodma_rb_set_threshold(sub, sub->compr_bytes,
|
||||
sub->threshold + bytes);
|
||||
if (!ret)
|
||||
sub->threshold += bytes;
|
||||
|
||||
aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
|
||||
aiodma_rb_clear_irq(sub);
|
||||
spin_unlock(&sub->lock);
|
||||
|
||||
snd_compr_fragment_elapsed(sub->cstream);
|
||||
}
|
||||
|
||||
static irqreturn_t aiodma_irq(int irq, void *p)
|
||||
{
|
||||
struct platform_device *pdev = p;
|
||||
struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < chip->num_aios; i++) {
|
||||
struct uniphier_aio *aio = &chip->aios[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
|
||||
struct uniphier_aio_sub *sub = &aio->sub[j];
|
||||
|
||||
/* Skip channel that does not trigger */
|
||||
if (!sub->running || !aiodma_rb_is_irq(sub))
|
||||
continue;
|
||||
|
||||
if (sub->substream)
|
||||
aiodma_pcm_irq(sub);
|
||||
if (sub->cstream)
|
||||
aiodma_compr_irq(sub);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uniphier_aiodma_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &uniphier_aiodma_hw);
|
||||
|
||||
return snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256);
|
||||
}
|
||||
|
||||
static int uniphier_aiodma_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
substream->runtime->dma_bytes = params_buffer_bytes(params);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aiodma_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
substream->runtime->dma_bytes = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aiodma_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
int bytes = runtime->period_size *
|
||||
runtime->channels * samples_to_bytes(runtime, 1);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = aiodma_ch_set_param(sub);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
ret = aiodma_rb_set_buffer(sub, runtime->dma_addr,
|
||||
runtime->dma_addr + runtime->dma_bytes,
|
||||
bytes);
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_aiodma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
struct device *dev = &aio->chip->pdev->dev;
|
||||
int bytes = runtime->period_size *
|
||||
runtime->channels * samples_to_bytes(runtime, 1);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes,
|
||||
bytes);
|
||||
aiodma_ch_set_enable(sub, 1);
|
||||
sub->running = 1;
|
||||
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
sub->running = 0;
|
||||
aiodma_ch_set_enable(sub, 0);
|
||||
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "Unknown trigger(%d) ignored\n", cmd);
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t uniphier_aiodma_pointer(
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
|
||||
struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
|
||||
int bytes = runtime->period_size *
|
||||
runtime->channels * samples_to_bytes(runtime, 1);
|
||||
unsigned long flags;
|
||||
snd_pcm_uframes_t pos;
|
||||
|
||||
spin_lock_irqsave(&sub->lock, flags);
|
||||
aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
|
||||
|
||||
if (sub->swm->dir == PORT_DIR_OUTPUT)
|
||||
pos = bytes_to_frames(runtime, sub->rd_offs);
|
||||
else
|
||||
pos = bytes_to_frames(runtime, sub->wr_offs);
|
||||
spin_unlock_irqrestore(&sub->lock, flags);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int uniphier_aiodma_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
|
||||
return remap_pfn_range(vma, vma->vm_start,
|
||||
substream->dma_buffer.addr >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static const struct snd_pcm_ops uniphier_aiodma_ops = {
|
||||
.open = uniphier_aiodma_open,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = uniphier_aiodma_hw_params,
|
||||
.hw_free = uniphier_aiodma_hw_free,
|
||||
.prepare = uniphier_aiodma_prepare,
|
||||
.trigger = uniphier_aiodma_trigger,
|
||||
.pointer = uniphier_aiodma_pointer,
|
||||
.mmap = uniphier_aiodma_mmap,
|
||||
};
|
||||
|
||||
static int uniphier_aiodma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct device *dev = rtd->card->snd_card->dev;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret;
|
||||
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return snd_pcm_lib_preallocate_pages_for_all(pcm,
|
||||
SNDRV_DMA_TYPE_DEV, dev,
|
||||
uniphier_aiodma_hw.buffer_bytes_max,
|
||||
uniphier_aiodma_hw.buffer_bytes_max);
|
||||
}
|
||||
|
||||
static void uniphier_aiodma_free(struct snd_pcm *pcm)
|
||||
{
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver uniphier_soc_platform = {
|
||||
.pcm_new = uniphier_aiodma_new,
|
||||
.pcm_free = uniphier_aiodma_free,
|
||||
.ops = &uniphier_aiodma_ops,
|
||||
.compr_ops = &uniphier_aio_compr_ops,
|
||||
};
|
||||
|
||||
static const struct regmap_config aiodma_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0x7fffc,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
/**
|
||||
* uniphier_aiodma_soc_register_platform - register the AIO DMA
|
||||
* @pdev: the platform device
|
||||
*
|
||||
* Register and setup the DMA of AIO to transfer the sound data to device.
|
||||
* This function need to call once at driver startup and need NOT to call
|
||||
* unregister function.
|
||||
*
|
||||
* Return: Zero if successful, otherwise a negative value on error.
|
||||
*/
|
||||
int uniphier_aiodma_soc_register_platform(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
void __iomem *preg;
|
||||
int irq, ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
preg = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(preg))
|
||||
return PTR_ERR(preg);
|
||||
|
||||
chip->regmap = devm_regmap_init_mmio(dev, preg,
|
||||
&aiodma_regmap_config);
|
||||
if (IS_ERR(chip->regmap))
|
||||
return PTR_ERR(chip->regmap);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Could not get irq.\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, aiodma_irq,
|
||||
IRQF_SHARED, dev_name(dev), pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_snd_soc_register_component(dev, &uniphier_soc_platform,
|
||||
NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uniphier_aiodma_soc_register_platform);
|
|
@ -0,0 +1,431 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Socionext UniPhier AIO ALSA driver for LD11/LD20.
|
||||
//
|
||||
// Copyright (c) 2016-2018 Socionext Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; version 2
|
||||
// of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "aio.h"
|
||||
|
||||
static const struct uniphier_aio_spec uniphier_aio_ld11[] = {
|
||||
/* for HDMI PCM In, Pin:AI1Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMIN1,
|
||||
.gname = AUD_GNAME_HDMI,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_INPUT,
|
||||
.rb = { 21, 14, },
|
||||
.ch = { 21, 14, },
|
||||
.iif = { 5, 3, },
|
||||
.iport = { 0, AUD_HW_PCMIN1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for SIF In, Pin:AI2Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMIN2,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_INPUT,
|
||||
.rb = { 22, 15, },
|
||||
.ch = { 22, 15, },
|
||||
.iif = { 6, 4, },
|
||||
.iport = { 1, AUD_HW_PCMIN2, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Line In, Pin:AI3Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMIN3,
|
||||
.gname = AUD_GNAME_LINE,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_EVE,
|
||||
.dir = PORT_DIR_INPUT,
|
||||
.rb = { 23, 16, },
|
||||
.ch = { 23, 16, },
|
||||
.iif = { 7, 5, },
|
||||
.iport = { 2, AUD_HW_PCMIN3, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for S/PDIF In, Pin:AI1IEC */
|
||||
{
|
||||
.name = AUD_NAME_IECIN1,
|
||||
.gname = AUD_GNAME_IEC,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_INPUT,
|
||||
.rb = { 26, 17, },
|
||||
.ch = { 26, 17, },
|
||||
.iif = { 10, 6, },
|
||||
.iport = { 3, AUD_HW_IECIN1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Speaker, Pin:AO1Dx */
|
||||
{
|
||||
.name = AUD_NAME_HPCMOUT1,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 0, 0, },
|
||||
.ch = { 0, 0, },
|
||||
.oif = { 0, 0, },
|
||||
.oport = { 0, AUD_HW_HPCMOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for HDMI PCM, Pin:AO2Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMOUT1,
|
||||
.gname = AUD_GNAME_HDMI,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 0, 0, },
|
||||
.ch = { 0, 0, },
|
||||
.oif = { 0, 0, },
|
||||
.oport = { 3, AUD_HW_PCMOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Line Out, Pin:LO2_x */
|
||||
{
|
||||
.name = AUD_NAME_PCMOUT2,
|
||||
.gname = AUD_GNAME_LINE,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_EVE,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 2, 2, },
|
||||
.ch = { 2, 2, },
|
||||
.oif = { 2, 2, },
|
||||
.oport = { 1, AUD_HW_PCMOUT2, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Headphone, Pin:HP1_x */
|
||||
{
|
||||
.name = AUD_NAME_PCMOUT3,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_EVE,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 3, 3, },
|
||||
.ch = { 3, 3, },
|
||||
.oif = { 3, 3, },
|
||||
.oport = { 2, AUD_HW_PCMOUT3, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for HW Sampling Rate Converter */
|
||||
{
|
||||
.name = AUD_NAME_EPCMOUT2,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_CONV,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 7, 5, },
|
||||
.ch = { 7, 5, },
|
||||
.oif = { 7, 5, },
|
||||
.oport = { 6, AUD_HW_EPCMOUT2, },
|
||||
.och = { 17, 12, },
|
||||
.iif = { 1, 1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for HW Sampling Rate Converter 2 */
|
||||
{
|
||||
.name = AUD_NAME_EPCMOUT3,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_CONV,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 8, 6, },
|
||||
.ch = { 8, 6, },
|
||||
.oif = { 8, 6, },
|
||||
.oport = { 7, AUD_HW_EPCMOUT3, },
|
||||
.och = { 18, 13, },
|
||||
.iif = { 2, 2, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for S/PDIF Out, Pin:AO1IEC */
|
||||
{
|
||||
.name = AUD_NAME_HIECOUT1,
|
||||
.gname = AUD_GNAME_IEC,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 1, 1, },
|
||||
.ch = { 1, 1, },
|
||||
.oif = { 1, 1, },
|
||||
.oport = { 12, AUD_HW_HIECOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for S/PDIF Out, Pin:AO1IEC, Compress */
|
||||
{
|
||||
.name = AUD_NAME_HIECCOMPOUT1,
|
||||
.gname = AUD_GNAME_IEC,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 1, 1, },
|
||||
.ch = { 1, 1, },
|
||||
.oif = { 1, 1, },
|
||||
.oport = { 12, AUD_HW_HIECOUT1, },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = {
|
||||
[AUD_PLL_A1] = { .enable = true, },
|
||||
[AUD_PLL_F1] = { .enable = true, },
|
||||
[AUD_PLL_A2] = { .enable = true, },
|
||||
[AUD_PLL_F2] = { .enable = true, },
|
||||
[AUD_PLL_APLL] = { .enable = true, },
|
||||
[AUD_PLL_RX0] = { .enable = true, },
|
||||
[AUD_PLL_USB0] = { .enable = true, },
|
||||
[AUD_PLL_HSC0] = { .enable = true, },
|
||||
};
|
||||
|
||||
static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uniphier_aio_dai_probe(dai);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
|
||||
{
|
||||
.name = AUD_GNAME_HDMI,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_PCMOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = AUD_NAME_PCMIN1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_32000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_PCMIN2,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.capture = {
|
||||
.stream_name = AUD_NAME_PCMIN2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_GNAME_LINE,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_PCMOUT2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = AUD_NAME_PCMIN3,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_HPCMOUT1,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_HPCMOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_PCMOUT3,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_PCMOUT3,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_HIECOUT1,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_HIECOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_spdif_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_EPCMOUT2,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_EPCMOUT2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_32000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_EPCMOUT3,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_EPCMOUT3,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_32000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_HIECCOMPOUT1,
|
||||
.probe = uniphier_aio_ld11_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.compress_new = snd_soc_new_compress,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_HIECCOMPOUT1,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &uniphier_aio_spdif_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct uniphier_aio_chip_spec uniphier_aio_ld11_spec = {
|
||||
.specs = uniphier_aio_ld11,
|
||||
.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
|
||||
.dais = uniphier_aio_dai_ld11,
|
||||
.num_dais = ARRAY_SIZE(uniphier_aio_dai_ld11),
|
||||
.plls = uniphier_aio_pll_ld11,
|
||||
.num_plls = ARRAY_SIZE(uniphier_aio_pll_ld11),
|
||||
.addr_ext = 0,
|
||||
};
|
||||
|
||||
static const struct uniphier_aio_chip_spec uniphier_aio_ld20_spec = {
|
||||
.specs = uniphier_aio_ld11,
|
||||
.num_specs = ARRAY_SIZE(uniphier_aio_ld11),
|
||||
.dais = uniphier_aio_dai_ld11,
|
||||
.num_dais = ARRAY_SIZE(uniphier_aio_dai_ld11),
|
||||
.plls = uniphier_aio_pll_ld11,
|
||||
.num_plls = ARRAY_SIZE(uniphier_aio_pll_ld11),
|
||||
.addr_ext = 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id uniphier_aio_of_match[] = {
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld11-aio",
|
||||
.data = &uniphier_aio_ld11_spec,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld20-aio",
|
||||
.data = &uniphier_aio_ld20_spec,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
|
||||
|
||||
static struct platform_driver uniphier_aio_driver = {
|
||||
.driver = {
|
||||
.name = "snd-uniphier-aio-ld11",
|
||||
.of_match_table = of_match_ptr(uniphier_aio_of_match),
|
||||
},
|
||||
.probe = uniphier_aio_probe,
|
||||
.remove = uniphier_aio_remove,
|
||||
};
|
||||
module_platform_driver(uniphier_aio_driver);
|
||||
|
||||
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier LD11/LD20 AIO driver.");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,320 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Socionext UniPhier AIO ALSA driver for PXs2.
|
||||
//
|
||||
// Copyright (c) 2018 Socionext Inc.
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "aio.h"
|
||||
|
||||
static const struct uniphier_aio_spec uniphier_aio_pxs2[] = {
|
||||
/* for Line PCM In, Pin:AI1Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMIN1,
|
||||
.gname = AUD_GNAME_LINE,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_INPUT,
|
||||
.rb = { 16, 11, },
|
||||
.ch = { 16, 11, },
|
||||
.iif = { 0, 0, },
|
||||
.iport = { 0, AUD_HW_PCMIN1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Speaker/Headphone/Mic PCM In, Pin:AI2Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMIN2,
|
||||
.gname = AUD_GNAME_AUX,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_INPUT,
|
||||
.rb = { 17, 12, },
|
||||
.ch = { 17, 12, },
|
||||
.iif = { 1, 1, },
|
||||
.iport = { 1, AUD_HW_PCMIN2, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for HDMI PCM Out, Pin:AO1Dx (inner) */
|
||||
{
|
||||
.name = AUD_NAME_HPCMOUT1,
|
||||
.gname = AUD_GNAME_HDMI,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 0, 0, },
|
||||
.ch = { 0, 0, },
|
||||
.oif = { 0, 0, },
|
||||
.oport = { 3, AUD_HW_HPCMOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Line PCM Out, Pin:AO2Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMOUT1,
|
||||
.gname = AUD_GNAME_LINE,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 1, 1, },
|
||||
.ch = { 1, 1, },
|
||||
.oif = { 1, 1, },
|
||||
.oport = { 0, AUD_HW_PCMOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for Speaker/Headphone/Mic PCM Out, Pin:AO3Dx */
|
||||
{
|
||||
.name = AUD_NAME_PCMOUT2,
|
||||
.gname = AUD_GNAME_AUX,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_I2S,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 2, 2, },
|
||||
.ch = { 2, 2, },
|
||||
.oif = { 2, 2, },
|
||||
.oport = { 1, AUD_HW_PCMOUT2, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for HDMI Out, Pin:AO1IEC */
|
||||
{
|
||||
.name = AUD_NAME_HIECOUT1,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 6, 4, },
|
||||
.ch = { 6, 4, },
|
||||
.oif = { 6, 4, },
|
||||
.oport = { 12, AUD_HW_HIECOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for HDMI Out, Pin:AO1IEC, Compress */
|
||||
{
|
||||
.name = AUD_NAME_HIECCOMPOUT1,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 6, 4, },
|
||||
.ch = { 6, 4, },
|
||||
.oif = { 6, 4, },
|
||||
.oport = { 12, AUD_HW_HIECOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for S/PDIF Out, Pin:AO2IEC */
|
||||
{
|
||||
.name = AUD_NAME_IECOUT1,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 7, 5, },
|
||||
.ch = { 7, 5, },
|
||||
.oif = { 7, 5, },
|
||||
.oport = { 13, AUD_HW_IECOUT1, },
|
||||
},
|
||||
},
|
||||
|
||||
/* for S/PDIF Out, Pin:AO2IEC */
|
||||
{
|
||||
.name = AUD_NAME_IECCOMPOUT1,
|
||||
.swm = {
|
||||
.type = PORT_TYPE_SPDIF,
|
||||
.dir = PORT_DIR_OUTPUT,
|
||||
.rb = { 7, 5, },
|
||||
.ch = { 7, 5, },
|
||||
.oif = { 7, 5, },
|
||||
.oport = { 13, AUD_HW_IECOUT1, },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = {
|
||||
[AUD_PLL_A1] = { .enable = true, },
|
||||
[AUD_PLL_F1] = { .enable = true, },
|
||||
[AUD_PLL_A2] = { .enable = true, },
|
||||
[AUD_PLL_F2] = { .enable = true, },
|
||||
[AUD_PLL_APLL] = { .enable = true, },
|
||||
[AUD_PLL_HSC0] = { .enable = true, },
|
||||
};
|
||||
|
||||
static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uniphier_aio_dai_probe(dai);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
|
||||
{
|
||||
.name = AUD_GNAME_HDMI,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_HPCMOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_GNAME_LINE,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_PCMOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = AUD_NAME_PCMIN1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_GNAME_AUX,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_PCMOUT2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = AUD_NAME_PCMIN2,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_i2s_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_HIECOUT1,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_HIECOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_spdif_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_IECOUT1,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_IECOUT1,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &uniphier_aio_spdif_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_HIECCOMPOUT1,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.compress_new = snd_soc_new_compress,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_HIECCOMPOUT1,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &uniphier_aio_spdif_ops,
|
||||
},
|
||||
{
|
||||
.name = AUD_NAME_IECCOMPOUT1,
|
||||
.probe = uniphier_aio_pxs2_probe,
|
||||
.remove = uniphier_aio_dai_remove,
|
||||
.suspend = uniphier_aio_dai_suspend,
|
||||
.resume = uniphier_aio_dai_resume,
|
||||
.compress_new = snd_soc_new_compress,
|
||||
.playback = {
|
||||
.stream_name = AUD_NAME_IECCOMPOUT1,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
},
|
||||
.ops = &uniphier_aio_spdif_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct uniphier_aio_chip_spec uniphier_aio_pxs2_spec = {
|
||||
.specs = uniphier_aio_pxs2,
|
||||
.num_specs = ARRAY_SIZE(uniphier_aio_pxs2),
|
||||
.dais = uniphier_aio_dai_pxs2,
|
||||
.num_dais = ARRAY_SIZE(uniphier_aio_dai_pxs2),
|
||||
.plls = uniphier_aio_pll_pxs2,
|
||||
.num_plls = ARRAY_SIZE(uniphier_aio_pll_pxs2),
|
||||
.addr_ext = 0,
|
||||
};
|
||||
|
||||
static const struct of_device_id uniphier_aio_of_match[] = {
|
||||
{
|
||||
.compatible = "socionext,uniphier-pxs2-aio",
|
||||
.data = &uniphier_aio_pxs2_spec,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_aio_of_match);
|
||||
|
||||
static struct platform_driver uniphier_aio_driver = {
|
||||
.driver = {
|
||||
.name = "snd-uniphier-aio-pxs2",
|
||||
.of_match_table = of_match_ptr(uniphier_aio_of_match),
|
||||
},
|
||||
.probe = uniphier_aio_probe,
|
||||
.remove = uniphier_aio_remove,
|
||||
};
|
||||
module_platform_driver(uniphier_aio_driver);
|
||||
|
||||
MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier PXs2 AIO driver.");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,465 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Socionext UniPhier AIO ALSA driver.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Socionext Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SND_UNIPHIER_AIO_REG_H__
|
||||
#define SND_UNIPHIER_AIO_REG_H__
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* soc-glue */
|
||||
#define SG_AOUTEN 0x1c04
|
||||
|
||||
/* SW view */
|
||||
#define A2CHNMAPCTR0(n) (0x00000 + 0x40 * (n))
|
||||
#define A2RBNMAPCTR0(n) (0x01000 + 0x40 * (n))
|
||||
#define A2IPORTNMAPCTR0(n) (0x02000 + 0x40 * (n))
|
||||
#define A2IPORTNMAPCTR1(n) (0x02004 + 0x40 * (n))
|
||||
#define A2IIFNMAPCTR0(n) (0x03000 + 0x40 * (n))
|
||||
#define A2OPORTNMAPCTR0(n) (0x04000 + 0x40 * (n))
|
||||
#define A2OPORTNMAPCTR1(n) (0x04004 + 0x40 * (n))
|
||||
#define A2OPORTNMAPCTR2(n) (0x04008 + 0x40 * (n))
|
||||
#define A2OIFNMAPCTR0(n) (0x05000 + 0x40 * (n))
|
||||
#define A2ATNMAPCTR0(n) (0x06000 + 0x40 * (n))
|
||||
|
||||
#define MAPCTR0_EN 0x80000000
|
||||
|
||||
/* CTL */
|
||||
#define A2APLLCTR0 0x07000
|
||||
#define A2APLLCTR0_APLLXPOW_MASK GENMASK(3, 0)
|
||||
#define A2APLLCTR0_APLLXPOW_PWOFF (0x0 << 0)
|
||||
#define A2APLLCTR0_APLLXPOW_PWON (0xf << 0)
|
||||
#define A2APLLCTR1 0x07004
|
||||
#define A2APLLCTR1_APLLX_MASK 0x00010101
|
||||
#define A2APLLCTR1_APLLX_36MHZ 0x00000000
|
||||
#define A2APLLCTR1_APLLX_33MHZ 0x00000001
|
||||
#define A2EXMCLKSEL0 0x07030
|
||||
#define A2EXMCLKSEL0_EXMCLK_MASK GENMASK(2, 0)
|
||||
#define A2EXMCLKSEL0_EXMCLK_OUTPUT (0x0 << 0)
|
||||
#define A2EXMCLKSEL0_EXMCLK_INPUT (0x7 << 0)
|
||||
#define A2SSIFSW 0x07050
|
||||
#define A2CH22_2CTR 0x07054
|
||||
#define A2AIOINPUTSEL 0x070e0
|
||||
#define A2AIOINPUTSEL_RXSEL_PCMI1_MASK GENMASK(2, 0)
|
||||
#define A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 (0x2 << 0)
|
||||
#define A2AIOINPUTSEL_RXSEL_PCMI2_MASK GENMASK(6, 4)
|
||||
#define A2AIOINPUTSEL_RXSEL_PCMI2_SIF (0x7 << 4)
|
||||
#define A2AIOINPUTSEL_RXSEL_PCMI3_MASK GENMASK(10, 8)
|
||||
#define A2AIOINPUTSEL_RXSEL_PCMI3_EVEA (0x1 << 8)
|
||||
#define A2AIOINPUTSEL_RXSEL_IECI1_MASK GENMASK(14, 12)
|
||||
#define A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1 (0x2 << 12)
|
||||
#define A2AIOINPUTSEL_RXSEL_MASK (A2AIOINPUTSEL_RXSEL_PCMI1_MASK | \
|
||||
A2AIOINPUTSEL_RXSEL_PCMI2_MASK | \
|
||||
A2AIOINPUTSEL_RXSEL_PCMI3_MASK | \
|
||||
A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1)
|
||||
|
||||
/* INTC */
|
||||
#define INTCHIM(m) (0x9028 + 0x80 * (m))
|
||||
#define INTRBIM(m) (0x9030 + 0x80 * (m))
|
||||
#define INTCHID(m) (0xa028 + 0x80 * (m))
|
||||
#define INTRBID(m) (0xa030 + 0x80 * (m))
|
||||
|
||||
/* AIN(PCMINN) */
|
||||
#define IPORTMXCTR1(n) (0x22000 + 0x400 * (n))
|
||||
#define IPORTMXCTR1_LRSEL_MASK GENMASK(11, 10)
|
||||
#define IPORTMXCTR1_LRSEL_RIGHT (0x0 << 10)
|
||||
#define IPORTMXCTR1_LRSEL_LEFT (0x1 << 10)
|
||||
#define IPORTMXCTR1_LRSEL_I2S (0x2 << 10)
|
||||
#define IPORTMXCTR1_OUTBITSEL_MASK (0x800003U << 8)
|
||||
#define IPORTMXCTR1_OUTBITSEL_32 (0x800000U << 8)
|
||||
#define IPORTMXCTR1_OUTBITSEL_24 (0x000000U << 8)
|
||||
#define IPORTMXCTR1_OUTBITSEL_20 (0x000001U << 8)
|
||||
#define IPORTMXCTR1_OUTBITSEL_16 (0x000002U << 8)
|
||||
#define IPORTMXCTR1_CHSEL_MASK GENMASK(6, 4)
|
||||
#define IPORTMXCTR1_CHSEL_ALL (0x0 << 4)
|
||||
#define IPORTMXCTR1_CHSEL_D0_D2 (0x1 << 4)
|
||||
#define IPORTMXCTR1_CHSEL_D0 (0x2 << 4)
|
||||
#define IPORTMXCTR1_CHSEL_D1 (0x3 << 4)
|
||||
#define IPORTMXCTR1_CHSEL_D2 (0x4 << 4)
|
||||
#define IPORTMXCTR1_CHSEL_DMIX (0x5 << 4)
|
||||
#define IPORTMXCTR1_FSSEL_MASK GENMASK(3, 0)
|
||||
#define IPORTMXCTR1_FSSEL_48 (0x0 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_96 (0x1 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_192 (0x2 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_32 (0x3 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_44_1 (0x4 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_88_2 (0x5 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_176_4 (0x6 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_16 (0x8 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_22_05 (0x9 << 0)
|
||||
#define IPORTMXCTR1_FSSEL_24 (0xa << 0)
|
||||
#define IPORTMXCTR1_FSSEL_8 (0xb << 0)
|
||||
#define IPORTMXCTR1_FSSEL_11_025 (0xc << 0)
|
||||
#define IPORTMXCTR1_FSSEL_12 (0xd << 0)
|
||||
#define IPORTMXCTR2(n) (0x22004 + 0x400 * (n))
|
||||
#define IPORTMXCTR2_ACLKSEL_MASK GENMASK(19, 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_A1 (0x0 << 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_F1 (0x1 << 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_A2 (0x2 << 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_F2 (0x3 << 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_A2PLL (0x4 << 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_RX1 (0x5 << 16)
|
||||
#define IPORTMXCTR2_ACLKSEL_RX2 (0x6 << 16)
|
||||
#define IPORTMXCTR2_MSSEL_MASK BIT(15)
|
||||
#define IPORTMXCTR2_MSSEL_SLAVE (0x0 << 15)
|
||||
#define IPORTMXCTR2_MSSEL_MASTER (0x1 << 15)
|
||||
#define IPORTMXCTR2_EXTLSIFSSEL_MASK BIT(14)
|
||||
#define IPORTMXCTR2_EXTLSIFSSEL_36 (0x0 << 14)
|
||||
#define IPORTMXCTR2_EXTLSIFSSEL_24 (0x1 << 14)
|
||||
#define IPORTMXCTR2_DACCKSEL_MASK GENMASK(9, 8)
|
||||
#define IPORTMXCTR2_DACCKSEL_1_2 (0x0 << 8)
|
||||
#define IPORTMXCTR2_DACCKSEL_1_3 (0x1 << 8)
|
||||
#define IPORTMXCTR2_DACCKSEL_1_1 (0x2 << 8)
|
||||
#define IPORTMXCTR2_DACCKSEL_2_3 (0x3 << 8)
|
||||
#define IPORTMXCTR2_REQEN_MASK BIT(0)
|
||||
#define IPORTMXCTR2_REQEN_DISABLE (0x0 << 0)
|
||||
#define IPORTMXCTR2_REQEN_ENABLE (0x1 << 0)
|
||||
#define IPORTMXCNTCTR(n) (0x22010 + 0x400 * (n))
|
||||
#define IPORTMXCOUNTER(n) (0x22014 + 0x400 * (n))
|
||||
#define IPORTMXCNTMONI(n) (0x22018 + 0x400 * (n))
|
||||
#define IPORTMXACLKSEL0EX(n) (0x22020 + 0x400 * (n))
|
||||
#define IPORTMXACLKSEL0EX_ACLKSEL0EX_MASK GENMASK(3, 0)
|
||||
#define IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL (0x0 << 0)
|
||||
#define IPORTMXACLKSEL0EX_ACLKSEL0EX_EXTERNAL (0xf << 0)
|
||||
#define IPORTMXEXNOE(n) (0x22070 + 0x400 * (n))
|
||||
#define IPORTMXEXNOE_PCMINOE_MASK BIT(0)
|
||||
#define IPORTMXEXNOE_PCMINOE_OUTPUT (0x0 << 0)
|
||||
#define IPORTMXEXNOE_PCMINOE_INPUT (0x1 << 0)
|
||||
#define IPORTMXMASK(n) (0x22078 + 0x400 * (n))
|
||||
#define IPORTMXMASK_IUXCKMSK_MASK GENMASK(18, 16)
|
||||
#define IPORTMXMASK_IUXCKMSK_ON (0x0 << 16)
|
||||
#define IPORTMXMASK_IUXCKMSK_OFF (0x7 << 16)
|
||||
#define IPORTMXMASK_XCKMSK_MASK GENMASK(2, 0)
|
||||
#define IPORTMXMASK_XCKMSK_ON (0x0 << 0)
|
||||
#define IPORTMXMASK_XCKMSK_OFF (0x7 << 0)
|
||||
#define IPORTMXRSTCTR(n) (0x2207c + 0x400 * (n))
|
||||
#define IPORTMXRSTCTR_RSTPI_MASK BIT(7)
|
||||
#define IPORTMXRSTCTR_RSTPI_RELEASE (0x0 << 7)
|
||||
#define IPORTMXRSTCTR_RSTPI_RESET (0x1 << 7)
|
||||
|
||||
/* AIN(PBinMX) */
|
||||
#define PBINMXCTR(n) (0x20200 + 0x40 * (n))
|
||||
#define PBINMXCTR_NCONNECT_MASK BIT(15)
|
||||
#define PBINMXCTR_NCONNECT_CONNECT (0x0 << 15)
|
||||
#define PBINMXCTR_NCONNECT_DISCONNECT (0x1 << 15)
|
||||
#define PBINMXCTR_INOUTSEL_MASK BIT(14)
|
||||
#define PBINMXCTR_INOUTSEL_IN (0x0 << 14)
|
||||
#define PBINMXCTR_INOUTSEL_OUT (0x1 << 14)
|
||||
#define PBINMXCTR_PBINSEL_SHIFT (8)
|
||||
#define PBINMXCTR_ENDIAN_MASK GENMASK(5, 4)
|
||||
#define PBINMXCTR_ENDIAN_3210 (0x0 << 4)
|
||||
#define PBINMXCTR_ENDIAN_0123 (0x1 << 4)
|
||||
#define PBINMXCTR_ENDIAN_1032 (0x2 << 4)
|
||||
#define PBINMXCTR_ENDIAN_2301 (0x3 << 4)
|
||||
#define PBINMXCTR_MEMFMT_MASK GENMASK(3, 0)
|
||||
#define PBINMXCTR_MEMFMT_D0 (0x0 << 0)
|
||||
#define PBINMXCTR_MEMFMT_5_1CH_DMIX (0x1 << 0)
|
||||
#define PBINMXCTR_MEMFMT_6CH (0x2 << 0)
|
||||
#define PBINMXCTR_MEMFMT_4CH (0x3 << 0)
|
||||
#define PBINMXCTR_MEMFMT_DMIX (0x4 << 0)
|
||||
#define PBINMXCTR_MEMFMT_1CH (0x5 << 0)
|
||||
#define PBINMXCTR_MEMFMT_16LR (0x6 << 0)
|
||||
#define PBINMXCTR_MEMFMT_7_1CH (0x7 << 0)
|
||||
#define PBINMXCTR_MEMFMT_7_1CH_DMIX (0x8 << 0)
|
||||
#define PBINMXCTR_MEMFMT_STREAM (0xf << 0)
|
||||
#define PBINMXPAUSECTR0(n) (0x20204 + 0x40 * (n))
|
||||
#define PBINMXPAUSECTR1(n) (0x20208 + 0x40 * (n))
|
||||
|
||||
/* AOUT */
|
||||
#define AOUTENCTR0 0x40040
|
||||
#define AOUTENCTR1 0x40044
|
||||
#define AOUTENCTR2 0x40048
|
||||
#define AOUTRSTCTR0 0x40060
|
||||
#define AOUTRSTCTR1 0x40064
|
||||
#define AOUTRSTCTR2 0x40068
|
||||
#define AOUTSRCRSTCTR0 0x400c0
|
||||
#define AOUTSRCRSTCTR1 0x400c4
|
||||
#define AOUTSRCRSTCTR2 0x400c8
|
||||
|
||||
/* AOUT(PCMOUTN) */
|
||||
#define OPORTMXCTR1(n) (0x42000 + 0x400 * (n))
|
||||
#define OPORTMXCTR1_I2SLRSEL_MASK (0x11 << 10)
|
||||
#define OPORTMXCTR1_I2SLRSEL_RIGHT (0x00 << 10)
|
||||
#define OPORTMXCTR1_I2SLRSEL_LEFT (0x01 << 10)
|
||||
#define OPORTMXCTR1_I2SLRSEL_I2S (0x11 << 10)
|
||||
#define OPORTMXCTR1_OUTBITSEL_MASK (0x800003U << 8)
|
||||
#define OPORTMXCTR1_OUTBITSEL_32 (0x800000U << 8)
|
||||
#define OPORTMXCTR1_OUTBITSEL_24 (0x000000U << 8)
|
||||
#define OPORTMXCTR1_OUTBITSEL_20 (0x000001U << 8)
|
||||
#define OPORTMXCTR1_OUTBITSEL_16 (0x000002U << 8)
|
||||
#define OPORTMXCTR1_FSSEL_MASK GENMASK(3, 0)
|
||||
#define OPORTMXCTR1_FSSEL_48 (0x0 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_96 (0x1 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_192 (0x2 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_32 (0x3 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_44_1 (0x4 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_88_2 (0x5 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_176_4 (0x6 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_16 (0x8 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_22_05 (0x9 << 0)
|
||||
#define OPORTMXCTR1_FSSEL_24 (0xa << 0)
|
||||
#define OPORTMXCTR1_FSSEL_8 (0xb << 0)
|
||||
#define OPORTMXCTR1_FSSEL_11_025 (0xc << 0)
|
||||
#define OPORTMXCTR1_FSSEL_12 (0xd << 0)
|
||||
#define OPORTMXCTR2(n) (0x42004 + 0x400 * (n))
|
||||
#define OPORTMXCTR2_ACLKSEL_MASK GENMASK(19, 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_A1 (0x0 << 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_F1 (0x1 << 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_A2 (0x2 << 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_F2 (0x3 << 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_A2PLL (0x4 << 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_RX1 (0x5 << 16)
|
||||
#define OPORTMXCTR2_ACLKSEL_RX2 (0x6 << 16)
|
||||
#define OPORTMXCTR2_MSSEL_MASK BIT(15)
|
||||
#define OPORTMXCTR2_MSSEL_SLAVE (0x0 << 15)
|
||||
#define OPORTMXCTR2_MSSEL_MASTER (0x1 << 15)
|
||||
#define OPORTMXCTR2_EXTLSIFSSEL_MASK BIT(14)
|
||||
#define OPORTMXCTR2_EXTLSIFSSEL_36 (0x0 << 14)
|
||||
#define OPORTMXCTR2_EXTLSIFSSEL_24 (0x1 << 14)
|
||||
#define OPORTMXCTR2_DACCKSEL_MASK GENMASK(9, 8)
|
||||
#define OPORTMXCTR2_DACCKSEL_1_2 (0x0 << 8)
|
||||
#define OPORTMXCTR2_DACCKSEL_1_3 (0x1 << 8)
|
||||
#define OPORTMXCTR2_DACCKSEL_1_1 (0x2 << 8)
|
||||
#define OPORTMXCTR2_DACCKSEL_2_3 (0x3 << 8)
|
||||
#define OPORTMXCTR3(n) (0x42008 + 0x400 * (n))
|
||||
#define OPORTMXCTR3_IECTHUR_MASK BIT(19)
|
||||
#define OPORTMXCTR3_IECTHUR_IECOUT (0x0 << 19)
|
||||
#define OPORTMXCTR3_IECTHUR_IECIN (0x1 << 19)
|
||||
#define OPORTMXCTR3_SRCSEL_MASK GENMASK(18, 16)
|
||||
#define OPORTMXCTR3_SRCSEL_PCM (0x0 << 16)
|
||||
#define OPORTMXCTR3_SRCSEL_STREAM (0x1 << 16)
|
||||
#define OPORTMXCTR3_SRCSEL_CDDTS (0x2 << 16)
|
||||
#define OPORTMXCTR3_VALID_MASK BIT(12)
|
||||
#define OPORTMXCTR3_VALID_PCM (0x0 << 12)
|
||||
#define OPORTMXCTR3_VALID_STREAM (0x1 << 12)
|
||||
#define OPORTMXCTR3_PMSEL_MASK BIT(3)
|
||||
#define OPORTMXCTR3_PMSEL_MUTE (0x0 << 3)
|
||||
#define OPORTMXCTR3_PMSEL_PAUSE (0x1 << 3)
|
||||
#define OPORTMXCTR3_PMSW_MASK BIT(2)
|
||||
#define OPORTMXCTR3_PMSW_MUTE_OFF (0x0 << 2)
|
||||
#define OPORTMXCTR3_PMSW_MUTE_ON (0x1 << 2)
|
||||
#define OPORTMXSRC1CTR(n) (0x4200c + 0x400 * (n))
|
||||
#define OPORTMXSRC1CTR_FSIIPNUM_SHIFT (24)
|
||||
#define OPORTMXSRC1CTR_THMODE_MASK BIT(23)
|
||||
#define OPORTMXSRC1CTR_THMODE_SRC (0x0 << 23)
|
||||
#define OPORTMXSRC1CTR_THMODE_BYPASS (0x1 << 23)
|
||||
#define OPORTMXSRC1CTR_LOCK_MASK BIT(16)
|
||||
#define OPORTMXSRC1CTR_LOCK_UNLOCK (0x0 << 16)
|
||||
#define OPORTMXSRC1CTR_LOCK_LOCK (0x1 << 16)
|
||||
#define OPORTMXSRC1CTR_SRCPATH_MASK BIT(15)
|
||||
#define OPORTMXSRC1CTR_SRCPATH_BYPASS (0x0 << 15)
|
||||
#define OPORTMXSRC1CTR_SRCPATH_CALC (0x1 << 15)
|
||||
#define OPORTMXSRC1CTR_SYNC_MASK BIT(14)
|
||||
#define OPORTMXSRC1CTR_SYNC_ASYNC (0x0 << 14)
|
||||
#define OPORTMXSRC1CTR_SYNC_SYNC (0x1 << 14)
|
||||
#define OPORTMXSRC1CTR_FSOCK_MASK GENMASK(11, 10)
|
||||
#define OPORTMXSRC1CTR_FSOCK_44_1 (0x0 << 10)
|
||||
#define OPORTMXSRC1CTR_FSOCK_48 (0x1 << 10)
|
||||
#define OPORTMXSRC1CTR_FSOCK_32 (0x2 << 10)
|
||||
#define OPORTMXSRC1CTR_FSICK_MASK GENMASK(9, 8)
|
||||
#define OPORTMXSRC1CTR_FSICK_44_1 (0x0 << 8)
|
||||
#define OPORTMXSRC1CTR_FSICK_48 (0x1 << 8)
|
||||
#define OPORTMXSRC1CTR_FSICK_32 (0x2 << 8)
|
||||
#define OPORTMXSRC1CTR_FSIIPSEL_MASK GENMASK(5, 4)
|
||||
#define OPORTMXSRC1CTR_FSIIPSEL_INNER (0x0 << 4)
|
||||
#define OPORTMXSRC1CTR_FSIIPSEL_OUTER (0x1 << 4)
|
||||
#define OPORTMXSRC1CTR_FSISEL_MASK GENMASK(3, 0)
|
||||
#define OPORTMXSRC1CTR_FSISEL_ACLK (0x0 << 0)
|
||||
#define OPORTMXSRC1CTR_FSISEL_DD (0x1 << 0)
|
||||
#define OPORTMXDSDMUTEDAT(n) (0x42020 + 0x400 * (n))
|
||||
#define OPORTMXDXDFREQMODE(n) (0x42024 + 0x400 * (n))
|
||||
#define OPORTMXDSDSEL(n) (0x42028 + 0x400 * (n))
|
||||
#define OPORTMXDSDPORT(n) (0x4202c + 0x400 * (n))
|
||||
#define OPORTMXACLKSEL0EX(n) (0x42030 + 0x400 * (n))
|
||||
#define OPORTMXPATH(n) (0x42040 + 0x400 * (n))
|
||||
#define OPORTMXSYNC(n) (0x42044 + 0x400 * (n))
|
||||
#define OPORTMXREPET(n) (0x42050 + 0x400 * (n))
|
||||
#define OPORTMXREPET_STRLENGTH_AC3 SBF_(IEC61937_FRM_STR_AC3, 16)
|
||||
#define OPORTMXREPET_STRLENGTH_MPA SBF_(IEC61937_FRM_STR_MPA, 16)
|
||||
#define OPORTMXREPET_STRLENGTH_MP3 SBF_(IEC61937_FRM_STR_MP3, 16)
|
||||
#define OPORTMXREPET_STRLENGTH_DTS1 SBF_(IEC61937_FRM_STR_DTS1, 16)
|
||||
#define OPORTMXREPET_STRLENGTH_DTS2 SBF_(IEC61937_FRM_STR_DTS2, 16)
|
||||
#define OPORTMXREPET_STRLENGTH_DTS3 SBF_(IEC61937_FRM_STR_DTS3, 16)
|
||||
#define OPORTMXREPET_STRLENGTH_AAC SBF_(IEC61937_FRM_STR_AAC, 16)
|
||||
#define OPORTMXREPET_PMLENGTH_AC3 SBF_(IEC61937_FRM_PAU_AC3, 0)
|
||||
#define OPORTMXREPET_PMLENGTH_MPA SBF_(IEC61937_FRM_PAU_MPA, 0)
|
||||
#define OPORTMXREPET_PMLENGTH_MP3 SBF_(IEC61937_FRM_PAU_MP3, 0)
|
||||
#define OPORTMXREPET_PMLENGTH_DTS1 SBF_(IEC61937_FRM_PAU_DTS1, 0)
|
||||
#define OPORTMXREPET_PMLENGTH_DTS2 SBF_(IEC61937_FRM_PAU_DTS2, 0)
|
||||
#define OPORTMXREPET_PMLENGTH_DTS3 SBF_(IEC61937_FRM_PAU_DTS3, 0)
|
||||
#define OPORTMXREPET_PMLENGTH_AAC SBF_(IEC61937_FRM_PAU_AAC, 0)
|
||||
#define OPORTMXPAUDAT(n) (0x42054 + 0x400 * (n))
|
||||
#define OPORTMXPAUDAT_PAUSEPC_CMN (IEC61937_PC_PAUSE << 16)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_AC3 (IEC61937_FRM_PAU_AC3 * 4)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_MPA (IEC61937_FRM_PAU_MPA * 4)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_MP3 (IEC61937_FRM_PAU_MP3 * 4)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_DTS1 (IEC61937_FRM_PAU_DTS1 * 4)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_DTS2 (IEC61937_FRM_PAU_DTS2 * 4)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_DTS3 (IEC61937_FRM_PAU_DTS3 * 4)
|
||||
#define OPORTMXPAUDAT_PAUSEPD_AAC (IEC61937_FRM_PAU_AAC * 4)
|
||||
#define OPORTMXRATE_I(n) (0x420e4 + 0x400 * (n))
|
||||
#define OPORTMXRATE_I_EQU_MASK BIT(31)
|
||||
#define OPORTMXRATE_I_EQU_NOTEQUAL (0x0 << 31)
|
||||
#define OPORTMXRATE_I_EQU_EQUAL (0x1 << 31)
|
||||
#define OPORTMXRATE_I_SRCBPMD_MASK BIT(29)
|
||||
#define OPORTMXRATE_I_SRCBPMD_BYPASS (0x0 << 29)
|
||||
#define OPORTMXRATE_I_SRCBPMD_SRC (0x1 << 29)
|
||||
#define OPORTMXRATE_I_LRCKSTP_MASK BIT(24)
|
||||
#define OPORTMXRATE_I_LRCKSTP_START (0x0 << 24)
|
||||
#define OPORTMXRATE_I_LRCKSTP_STOP (0x1 << 24)
|
||||
#define OPORTMXRATE_I_ACLKSRC_MASK GENMASK(15, 12)
|
||||
#define OPORTMXRATE_I_ACLKSRC_APLL (0x0 << 12)
|
||||
#define OPORTMXRATE_I_ACLKSRC_USB (0x1 << 12)
|
||||
#define OPORTMXRATE_I_ACLKSRC_HSC (0x3 << 12)
|
||||
/* if OPORTMXRATE_I_ACLKSRC_APLL */
|
||||
#define OPORTMXRATE_I_ACLKSEL_MASK GENMASK(11, 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_APLLA1 (0x0 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_APLLF1 (0x1 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_APLLA2 (0x2 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_APLLF2 (0x3 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_APLL (0x4 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_HDMI1 (0x5 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_HDMI2 (0x6 << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_AI1ADCCK (0xc << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_AI2ADCCK (0xd << 8)
|
||||
#define OPORTMXRATE_I_ACLKSEL_AI3ADCCK (0xe << 8)
|
||||
#define OPORTMXRATE_I_MCKSEL_MASK GENMASK(7, 4)
|
||||
#define OPORTMXRATE_I_MCKSEL_36 (0x0 << 4)
|
||||
#define OPORTMXRATE_I_MCKSEL_33 (0x1 << 4)
|
||||
#define OPORTMXRATE_I_MCKSEL_HSC27 (0xb << 4)
|
||||
#define OPORTMXRATE_I_FSSEL_MASK GENMASK(3, 0)
|
||||
#define OPORTMXRATE_I_FSSEL_48 (0x0 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_96 (0x1 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_192 (0x2 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_32 (0x3 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_44_1 (0x4 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_88_2 (0x5 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_176_4 (0x6 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_16 (0x8 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_22_05 (0x9 << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_24 (0xa << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_8 (0xb << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_11_025 (0xc << 0)
|
||||
#define OPORTMXRATE_I_FSSEL_12 (0xd << 0)
|
||||
#define OPORTMXEXNOE(n) (0x420f0 + 0x400 * (n))
|
||||
#define OPORTMXMASK(n) (0x420f8 + 0x400 * (n))
|
||||
#define OPORTMXMASK_IUDXMSK_MASK GENMASK(28, 24)
|
||||
#define OPORTMXMASK_IUDXMSK_ON (0x00 << 24)
|
||||
#define OPORTMXMASK_IUDXMSK_OFF (0x1f << 24)
|
||||
#define OPORTMXMASK_IUXCKMSK_MASK GENMASK(18, 16)
|
||||
#define OPORTMXMASK_IUXCKMSK_ON (0x0 << 16)
|
||||
#define OPORTMXMASK_IUXCKMSK_OFF (0x7 << 16)
|
||||
#define OPORTMXMASK_DXMSK_MASK GENMASK(12, 8)
|
||||
#define OPORTMXMASK_DXMSK_ON (0x00 << 8)
|
||||
#define OPORTMXMASK_DXMSK_OFF (0x1f << 8)
|
||||
#define OPORTMXMASK_XCKMSK_MASK GENMASK(2, 0)
|
||||
#define OPORTMXMASK_XCKMSK_ON (0x0 << 0)
|
||||
#define OPORTMXMASK_XCKMSK_OFF (0x7 << 0)
|
||||
#define OPORTMXDEBUG(n) (0x420fc + 0x400 * (n))
|
||||
#define OPORTMXT0RSTCTR(n) (0x4211c + 0x400 * (n))
|
||||
#define OPORTMXT1RSTCTR(n) (0x4213c + 0x400 * (n))
|
||||
#define OPORTMXT2RSTCTR(n) (0x4215c + 0x400 * (n))
|
||||
#define OPORTMXT3RSTCTR(n) (0x4217c + 0x400 * (n))
|
||||
#define OPORTMXT4RSTCTR(n) (0x4219c + 0x400 * (n))
|
||||
|
||||
#define SBF_(frame, shift) (((frame) * 2 - 1) << shift)
|
||||
|
||||
/* AOUT(PBoutMX) */
|
||||
#define PBOUTMXCTR0(n) (0x40200 + 0x40 * (n))
|
||||
#define PBOUTMXCTR0_ENDIAN_MASK GENMASK(5, 4)
|
||||
#define PBOUTMXCTR0_ENDIAN_3210 (0x0 << 4)
|
||||
#define PBOUTMXCTR0_ENDIAN_0123 (0x1 << 4)
|
||||
#define PBOUTMXCTR0_ENDIAN_1032 (0x2 << 4)
|
||||
#define PBOUTMXCTR0_ENDIAN_2301 (0x3 << 4)
|
||||
#define PBOUTMXCTR0_MEMFMT_MASK GENMASK(3, 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_10CH (0x0 << 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_8CH (0x1 << 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_6CH (0x2 << 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_4CH (0x3 << 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_2CH (0x4 << 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_STREAM (0x5 << 0)
|
||||
#define PBOUTMXCTR0_MEMFMT_1CH (0x6 << 0)
|
||||
#define PBOUTMXCTR1(n) (0x40204 + 0x40 * (n))
|
||||
#define PBOUTMXINTCTR(n) (0x40208 + 0x40 * (n))
|
||||
|
||||
/* A2D(subsystem) */
|
||||
#define CDA2D_STRT0 0x10000
|
||||
#define CDA2D_STRT0_STOP_MASK BIT(31)
|
||||
#define CDA2D_STRT0_STOP_START (0x0 << 31)
|
||||
#define CDA2D_STRT0_STOP_STOP (0x1 << 31)
|
||||
#define CDA2D_STAT0 0x10020
|
||||
#define CDA2D_TEST 0x100a0
|
||||
#define CDA2D_TEST_DDR_MODE_MASK GENMASK(3, 2)
|
||||
#define CDA2D_TEST_DDR_MODE_EXTON0 (0x0 << 2)
|
||||
#define CDA2D_TEST_DDR_MODE_EXTOFF1 (0x3 << 2)
|
||||
#define CDA2D_STRTADRSLOAD 0x100b0
|
||||
|
||||
#define CDA2D_CHMXCTRL1(n) (0x12000 + 0x80 * (n))
|
||||
#define CDA2D_CHMXCTRL1_INDSIZE_MASK BIT(0)
|
||||
#define CDA2D_CHMXCTRL1_INDSIZE_FINITE (0x0 << 0)
|
||||
#define CDA2D_CHMXCTRL1_INDSIZE_INFINITE (0x1 << 0)
|
||||
#define CDA2D_CHMXCTRL2(n) (0x12004 + 0x80 * (n))
|
||||
#define CDA2D_CHMXSRCAMODE(n) (0x12020 + 0x80 * (n))
|
||||
#define CDA2D_CHMXDSTAMODE(n) (0x12024 + 0x80 * (n))
|
||||
#define CDA2D_CHMXAMODE_ENDIAN_MASK GENMASK(17, 16)
|
||||
#define CDA2D_CHMXAMODE_ENDIAN_3210 (0x0 << 16)
|
||||
#define CDA2D_CHMXAMODE_ENDIAN_0123 (0x1 << 16)
|
||||
#define CDA2D_CHMXAMODE_ENDIAN_1032 (0x2 << 16)
|
||||
#define CDA2D_CHMXAMODE_ENDIAN_2301 (0x3 << 16)
|
||||
#define CDA2D_CHMXAMODE_RSSEL_SHIFT (8)
|
||||
#define CDA2D_CHMXAMODE_AUPDT_MASK GENMASK(5, 4)
|
||||
#define CDA2D_CHMXAMODE_AUPDT_INC (0x0 << 4)
|
||||
#define CDA2D_CHMXAMODE_AUPDT_FIX (0x2 << 4)
|
||||
#define CDA2D_CHMXAMODE_TYPE_MASK GENMASK(3, 2)
|
||||
#define CDA2D_CHMXAMODE_TYPE_NORMAL (0x0 << 2)
|
||||
#define CDA2D_CHMXAMODE_TYPE_RING (0x1 << 2)
|
||||
#define CDA2D_CHMXSRCSTRTADRS(n) (0x12030 + 0x80 * (n))
|
||||
#define CDA2D_CHMXSRCSTRTADRSU(n) (0x12034 + 0x80 * (n))
|
||||
#define CDA2D_CHMXDSTSTRTADRS(n) (0x12038 + 0x80 * (n))
|
||||
#define CDA2D_CHMXDSTSTRTADRSU(n) (0x1203c + 0x80 * (n))
|
||||
|
||||
/* A2D(ring buffer) */
|
||||
#define CDA2D_RBFLUSH0 0x10040
|
||||
#define CDA2D_RBADRSLOAD 0x100b4
|
||||
#define CDA2D_RDPTRLOAD 0x100b8
|
||||
#define CDA2D_RDPTRLOAD_LSFLAG_LOAD (0x0 << 31)
|
||||
#define CDA2D_RDPTRLOAD_LSFLAG_STORE (0x1 << 31)
|
||||
#define CDA2D_WRPTRLOAD 0x100bc
|
||||
#define CDA2D_WRPTRLOAD_LSFLAG_LOAD (0x0 << 31)
|
||||
#define CDA2D_WRPTRLOAD_LSFLAG_STORE (0x1 << 31)
|
||||
|
||||
#define CDA2D_RBMXBGNADRS(n) (0x14000 + 0x80 * (n))
|
||||
#define CDA2D_RBMXBGNADRSU(n) (0x14004 + 0x80 * (n))
|
||||
#define CDA2D_RBMXENDADRS(n) (0x14008 + 0x80 * (n))
|
||||
#define CDA2D_RBMXENDADRSU(n) (0x1400c + 0x80 * (n))
|
||||
#define CDA2D_RBMXBTH(n) (0x14038 + 0x80 * (n))
|
||||
#define CDA2D_RBMXRTH(n) (0x1403c + 0x80 * (n))
|
||||
#define CDA2D_RBMXRDPTR(n) (0x14020 + 0x80 * (n))
|
||||
#define CDA2D_RBMXRDPTRU(n) (0x14024 + 0x80 * (n))
|
||||
#define CDA2D_RBMXWRPTR(n) (0x14028 + 0x80 * (n))
|
||||
#define CDA2D_RBMXWRPTRU(n) (0x1402c + 0x80 * (n))
|
||||
#define CDA2D_RBMXPTRU_PTRU_MASK GENMASK(1, 0)
|
||||
#define CDA2D_RBMXCNFG(n) (0x14030 + 0x80 * (n))
|
||||
#define CDA2D_RBMXIR(n) (0x14014 + 0x80 * (n))
|
||||
#define CDA2D_RBMXIE(n) (0x14018 + 0x80 * (n))
|
||||
#define CDA2D_RBMXID(n) (0x1401c + 0x80 * (n))
|
||||
#define CDA2D_RBMXIX_SPACE BIT(3)
|
||||
#define CDA2D_RBMXIX_REMAIN BIT(4)
|
||||
|
||||
#endif /* SND_UNIPHIER_AIO_REG_H__ */
|
|
@ -0,0 +1,359 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Socionext UniPhier AIO ALSA driver.
|
||||
*
|
||||
* Copyright (c) 2016-2018 Socionext Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SND_UNIPHIER_AIO_H__
|
||||
#define SND_UNIPHIER_AIO_H__
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
struct platform_device;
|
||||
|
||||
enum ID_PORT_TYPE {
|
||||
PORT_TYPE_UNKNOWN,
|
||||
PORT_TYPE_I2S,
|
||||
PORT_TYPE_SPDIF,
|
||||
PORT_TYPE_EVE,
|
||||
PORT_TYPE_CONV,
|
||||
};
|
||||
|
||||
enum ID_PORT_DIR {
|
||||
PORT_DIR_OUTPUT,
|
||||
PORT_DIR_INPUT,
|
||||
};
|
||||
|
||||
enum IEC61937_PC {
|
||||
IEC61937_PC_AC3 = 0x0001,
|
||||
IEC61937_PC_PAUSE = 0x0003,
|
||||
IEC61937_PC_MPA = 0x0004,
|
||||
IEC61937_PC_MP3 = 0x0005,
|
||||
IEC61937_PC_DTS1 = 0x000b,
|
||||
IEC61937_PC_DTS2 = 0x000c,
|
||||
IEC61937_PC_DTS3 = 0x000d,
|
||||
IEC61937_PC_AAC = 0x0007,
|
||||
};
|
||||
|
||||
/* IEC61937 Repetition period of data-burst in IEC60958 frames */
|
||||
#define IEC61937_FRM_STR_AC3 1536
|
||||
#define IEC61937_FRM_STR_MPA 1152
|
||||
#define IEC61937_FRM_STR_MP3 1152
|
||||
#define IEC61937_FRM_STR_DTS1 512
|
||||
#define IEC61937_FRM_STR_DTS2 1024
|
||||
#define IEC61937_FRM_STR_DTS3 2048
|
||||
#define IEC61937_FRM_STR_AAC 1024
|
||||
|
||||
/* IEC61937 Repetition period of Pause data-burst in IEC60958 frames */
|
||||
#define IEC61937_FRM_PAU_AC3 3
|
||||
#define IEC61937_FRM_PAU_MPA 32
|
||||
#define IEC61937_FRM_PAU_MP3 32
|
||||
#define IEC61937_FRM_PAU_DTS1 3
|
||||
#define IEC61937_FRM_PAU_DTS2 3
|
||||
#define IEC61937_FRM_PAU_DTS3 3
|
||||
#define IEC61937_FRM_PAU_AAC 32
|
||||
|
||||
/* IEC61937 Pa and Pb */
|
||||
#define IEC61937_HEADER_SIGN 0x1f4e72f8
|
||||
|
||||
#define AUD_HW_PCMIN1 0
|
||||
#define AUD_HW_PCMIN2 1
|
||||
#define AUD_HW_PCMIN3 2
|
||||
#define AUD_HW_IECIN1 3
|
||||
#define AUD_HW_DIECIN1 4
|
||||
|
||||
#define AUD_NAME_PCMIN1 "aio-pcmin1"
|
||||
#define AUD_NAME_PCMIN2 "aio-pcmin2"
|
||||
#define AUD_NAME_PCMIN3 "aio-pcmin3"
|
||||
#define AUD_NAME_IECIN1 "aio-iecin1"
|
||||
#define AUD_NAME_DIECIN1 "aio-diecin1"
|
||||
|
||||
#define AUD_HW_HPCMOUT1 0
|
||||
#define AUD_HW_PCMOUT1 1
|
||||
#define AUD_HW_PCMOUT2 2
|
||||
#define AUD_HW_PCMOUT3 3
|
||||
#define AUD_HW_EPCMOUT1 4
|
||||
#define AUD_HW_EPCMOUT2 5
|
||||
#define AUD_HW_EPCMOUT3 6
|
||||
#define AUD_HW_EPCMOUT6 9
|
||||
#define AUD_HW_HIECOUT1 10
|
||||
#define AUD_HW_IECOUT1 11
|
||||
#define AUD_HW_CMASTER 31
|
||||
|
||||
#define AUD_NAME_HPCMOUT1 "aio-hpcmout1"
|
||||
#define AUD_NAME_PCMOUT1 "aio-pcmout1"
|
||||
#define AUD_NAME_PCMOUT2 "aio-pcmout2"
|
||||
#define AUD_NAME_PCMOUT3 "aio-pcmout3"
|
||||
#define AUD_NAME_EPCMOUT1 "aio-epcmout1"
|
||||
#define AUD_NAME_EPCMOUT2 "aio-epcmout2"
|
||||
#define AUD_NAME_EPCMOUT3 "aio-epcmout3"
|
||||
#define AUD_NAME_EPCMOUT6 "aio-epcmout6"
|
||||
#define AUD_NAME_HIECOUT1 "aio-hiecout1"
|
||||
#define AUD_NAME_IECOUT1 "aio-iecout1"
|
||||
#define AUD_NAME_CMASTER "aio-cmaster"
|
||||
#define AUD_NAME_HIECCOMPOUT1 "aio-hieccompout1"
|
||||
#define AUD_NAME_IECCOMPOUT1 "aio-ieccompout1"
|
||||
|
||||
#define AUD_GNAME_HDMI "aio-hdmi"
|
||||
#define AUD_GNAME_LINE "aio-line"
|
||||
#define AUD_GNAME_AUX "aio-aux"
|
||||
#define AUD_GNAME_IEC "aio-iec"
|
||||
|
||||
#define AUD_CLK_IO 0
|
||||
#define AUD_CLK_A1 1
|
||||
#define AUD_CLK_F1 2
|
||||
#define AUD_CLK_A2 3
|
||||
#define AUD_CLK_F2 4
|
||||
#define AUD_CLK_A 5
|
||||
#define AUD_CLK_F 6
|
||||
#define AUD_CLK_APLL 7
|
||||
#define AUD_CLK_RX0 8
|
||||
#define AUD_CLK_USB0 9
|
||||
#define AUD_CLK_HSC0 10
|
||||
|
||||
#define AUD_PLL_A1 0
|
||||
#define AUD_PLL_F1 1
|
||||
#define AUD_PLL_A2 2
|
||||
#define AUD_PLL_F2 3
|
||||
#define AUD_PLL_APLL 4
|
||||
#define AUD_PLL_RX0 5
|
||||
#define AUD_PLL_USB0 6
|
||||
#define AUD_PLL_HSC0 7
|
||||
|
||||
#define AUD_PLLDIV_1_2 0
|
||||
#define AUD_PLLDIV_1_3 1
|
||||
#define AUD_PLLDIV_1_1 2
|
||||
#define AUD_PLLDIV_2_3 3
|
||||
|
||||
#define AUD_RING_SIZE (128 * 1024)
|
||||
|
||||
#define AUD_MIN_FRAGMENT 4
|
||||
#define AUD_MAX_FRAGMENT 8
|
||||
#define AUD_MIN_FRAGMENT_SIZE (4 * 1024)
|
||||
#define AUD_MAX_FRAGMENT_SIZE (16 * 1024)
|
||||
|
||||
/*
|
||||
* This is a selector for virtual register map of AIO.
|
||||
*
|
||||
* map: Specify the index of virtual register map.
|
||||
* hw : Specify the ID of real register map, selector uses this value.
|
||||
* A meaning of this value depends specification of SoC.
|
||||
*/
|
||||
struct uniphier_aio_selector {
|
||||
int map;
|
||||
int hw;
|
||||
};
|
||||
|
||||
/**
|
||||
* 'SoftWare MAPping' setting of UniPhier AIO registers.
|
||||
*
|
||||
* We have to setup 'virtual' register maps to access 'real' registers of AIO.
|
||||
* This feature is legacy and meaningless but AIO needs this to work.
|
||||
*
|
||||
* Each hardware blocks have own virtual register maps as following:
|
||||
*
|
||||
* Address Virtual Real
|
||||
* ------- --------- ---------------
|
||||
* 0x12000 DMAC map0 --> [selector] --> DMAC hardware 3
|
||||
* 0x12080 DMAC map1 --> [selector] --> DMAC hardware 1
|
||||
* ...
|
||||
* 0x42000 Port map0 --> [selector] --> Port hardware 1
|
||||
* 0x42400 Port map1 --> [selector] --> Port hardware 2
|
||||
* ...
|
||||
*
|
||||
* ch : Input or output channel of DMAC
|
||||
* rb : Ring buffer
|
||||
* iport: PCM input port
|
||||
* iif : Input interface
|
||||
* oport: PCM output port
|
||||
* oif : Output interface
|
||||
* och : Output channel of DMAC for sampling rate converter
|
||||
*
|
||||
* These are examples for sound data paths:
|
||||
*
|
||||
* For caputure device:
|
||||
* (outer of AIO) -> iport -> iif -> ch -> rb -> (CPU)
|
||||
* For playback device:
|
||||
* (CPU) -> rb -> ch -> oif -> oport -> (outer of AIO)
|
||||
* For sampling rate converter device:
|
||||
* (CPU) -> rb -> ch -> oif -> (HW SRC) -> iif -> och -> orb -> (CPU)
|
||||
*/
|
||||
struct uniphier_aio_swmap {
|
||||
int type;
|
||||
int dir;
|
||||
|
||||
struct uniphier_aio_selector ch;
|
||||
struct uniphier_aio_selector rb;
|
||||
struct uniphier_aio_selector iport;
|
||||
struct uniphier_aio_selector iif;
|
||||
struct uniphier_aio_selector oport;
|
||||
struct uniphier_aio_selector oif;
|
||||
struct uniphier_aio_selector och;
|
||||
};
|
||||
|
||||
struct uniphier_aio_spec {
|
||||
const char *name;
|
||||
const char *gname;
|
||||
struct uniphier_aio_swmap swm;
|
||||
};
|
||||
|
||||
struct uniphier_aio_pll {
|
||||
bool enable;
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
struct uniphier_aio_chip_spec {
|
||||
const struct uniphier_aio_spec *specs;
|
||||
int num_specs;
|
||||
const struct uniphier_aio_pll *plls;
|
||||
int num_plls;
|
||||
struct snd_soc_dai_driver *dais;
|
||||
int num_dais;
|
||||
|
||||
/* DMA access mode, this is workaround for DMA hungup */
|
||||
int addr_ext;
|
||||
};
|
||||
|
||||
struct uniphier_aio_sub {
|
||||
struct uniphier_aio *aio;
|
||||
|
||||
/* Guard sub->rd_offs and wr_offs from IRQ handler. */
|
||||
spinlock_t lock;
|
||||
|
||||
const struct uniphier_aio_swmap *swm;
|
||||
const struct uniphier_aio_spec *spec;
|
||||
|
||||
/* For PCM audio */
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_pcm_hw_params params;
|
||||
|
||||
/* For compress audio */
|
||||
struct snd_compr_stream *cstream;
|
||||
struct snd_compr_params cparams;
|
||||
unsigned char *compr_area;
|
||||
dma_addr_t compr_addr;
|
||||
size_t compr_bytes;
|
||||
int pass_through;
|
||||
enum IEC61937_PC iec_pc;
|
||||
bool iec_header;
|
||||
|
||||
/* Both PCM and compress audio */
|
||||
bool use_mmap;
|
||||
int setting;
|
||||
int running;
|
||||
u64 rd_offs;
|
||||
u64 wr_offs;
|
||||
u32 threshold;
|
||||
u64 rd_org;
|
||||
u64 wr_org;
|
||||
u64 rd_total;
|
||||
u64 wr_total;
|
||||
};
|
||||
|
||||
struct uniphier_aio {
|
||||
struct uniphier_aio_chip *chip;
|
||||
|
||||
struct uniphier_aio_sub sub[2];
|
||||
|
||||
unsigned int fmt;
|
||||
/* Set one of AUD_CLK_X */
|
||||
int clk_in;
|
||||
int clk_out;
|
||||
/* Set one of AUD_PLL_X */
|
||||
int pll_in;
|
||||
int pll_out;
|
||||
/* Set one of AUD_PLLDIV_X */
|
||||
int plldiv;
|
||||
};
|
||||
|
||||
struct uniphier_aio_chip {
|
||||
struct platform_device *pdev;
|
||||
const struct uniphier_aio_chip_spec *chip_spec;
|
||||
|
||||
struct uniphier_aio *aios;
|
||||
int num_aios;
|
||||
struct uniphier_aio_pll *plls;
|
||||
int num_plls;
|
||||
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap_sg;
|
||||
int active;
|
||||
};
|
||||
|
||||
static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct uniphier_aio_chip *chip = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
return &chip->aios[dai->id];
|
||||
}
|
||||
|
||||
int uniphier_aiodma_soc_register_platform(struct platform_device *pdev);
|
||||
extern const struct snd_compr_ops uniphier_aio_compr_ops;
|
||||
|
||||
int uniphier_aio_dai_probe(struct snd_soc_dai *dai);
|
||||
int uniphier_aio_dai_remove(struct snd_soc_dai *dai);
|
||||
int uniphier_aio_dai_suspend(struct snd_soc_dai *dai);
|
||||
int uniphier_aio_dai_resume(struct snd_soc_dai *dai);
|
||||
int uniphier_aio_probe(struct platform_device *pdev);
|
||||
int uniphier_aio_remove(struct platform_device *pdev);
|
||||
extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops;
|
||||
extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops;
|
||||
|
||||
u64 aio_rb_cnt(struct uniphier_aio_sub *sub);
|
||||
u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub);
|
||||
u64 aio_rb_space(struct uniphier_aio_sub *sub);
|
||||
u64 aio_rb_space_to_end(struct uniphier_aio_sub *sub);
|
||||
|
||||
void aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable);
|
||||
int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
|
||||
unsigned int freq);
|
||||
void aio_chip_init(struct uniphier_aio_chip *chip);
|
||||
int aio_init(struct uniphier_aio_sub *sub);
|
||||
void aio_port_reset(struct uniphier_aio_sub *sub);
|
||||
int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate);
|
||||
int aio_port_set_fmt(struct uniphier_aio_sub *sub);
|
||||
int aio_port_set_clk(struct uniphier_aio_sub *sub);
|
||||
int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
|
||||
const struct snd_pcm_hw_params *params);
|
||||
void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
|
||||
int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through);
|
||||
int aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
|
||||
enum IEC61937_PC pc);
|
||||
void aio_src_reset(struct uniphier_aio_sub *sub);
|
||||
int aio_src_set_param(struct uniphier_aio_sub *sub,
|
||||
const struct snd_pcm_hw_params *params);
|
||||
int aio_srcif_set_param(struct uniphier_aio_sub *sub);
|
||||
int aio_srcch_set_param(struct uniphier_aio_sub *sub);
|
||||
void aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable);
|
||||
|
||||
int aiodma_ch_set_param(struct uniphier_aio_sub *sub);
|
||||
void aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable);
|
||||
int aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th);
|
||||
int aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
|
||||
int period);
|
||||
void aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
|
||||
int period);
|
||||
bool aiodma_rb_is_irq(struct uniphier_aio_sub *sub);
|
||||
void aiodma_rb_clear_irq(struct uniphier_aio_sub *sub);
|
||||
|
||||
#endif /* SND_UNIPHIER_AIO_H__ */
|
|
@ -1,22 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Socionext UniPhier EVEA ADC/DAC codec driver.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Socionext Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//
|
||||
// Socionext UniPhier EVEA ADC/DAC codec driver.
|
||||
//
|
||||
// Copyright (c) 2016-2017 Socionext Inc.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -32,6 +18,8 @@
|
|||
|
||||
#define AADCPOW(n) (0x0078 + 0x04 * (n))
|
||||
#define AADCPOW_AADC_POWD BIT(0)
|
||||
#define ALINSW1 0x0088
|
||||
#define ALINSW1_SEL1_SHIFT 3
|
||||
#define AHPOUTPOW 0x0098
|
||||
#define AHPOUTPOW_HP_ON BIT(4)
|
||||
#define ALINEPOW 0x009c
|
||||
|
@ -220,8 +208,8 @@ static void evea_update_switch_all(struct evea_priv *evea)
|
|||
static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.integer.value[0] = evea->switch_lin;
|
||||
|
||||
|
@ -231,8 +219,8 @@ static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
|
|||
static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (evea->switch_lin == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
@ -245,8 +233,8 @@ static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
|
|||
static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.integer.value[0] = evea->switch_lo;
|
||||
|
||||
|
@ -256,8 +244,8 @@ static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
|
|||
static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (evea->switch_lo == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
@ -270,8 +258,8 @@ static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
|
|||
static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.integer.value[0] = evea->switch_hp;
|
||||
|
||||
|
@ -281,8 +269,8 @@ static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
|
|||
static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (evea->switch_hp == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
@ -292,7 +280,16 @@ static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
|
|||
return evea_update_switch_hp(evea);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new eva_controls[] = {
|
||||
static const char * const linsw1_sel1_text[] = {
|
||||
"LIN1", "LIN2", "LIN3"
|
||||
};
|
||||
|
||||
static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
|
||||
ALINSW1, ALINSW1_SEL1_SHIFT,
|
||||
linsw1_sel1_text);
|
||||
|
||||
static const struct snd_kcontrol_new evea_controls[] = {
|
||||
SOC_ENUM("Line Capture Source", linsw1_sel1_enum),
|
||||
SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0,
|
||||
evea_get_switch_lin, evea_set_switch_lin),
|
||||
SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0,
|
||||
|
@ -301,9 +298,9 @@ static const struct snd_kcontrol_new eva_controls[] = {
|
|||
evea_get_switch_hp, evea_set_switch_hp),
|
||||
};
|
||||
|
||||
static int evea_codec_probe(struct snd_soc_codec *codec)
|
||||
static int evea_codec_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
evea->switch_lin = 1;
|
||||
evea->switch_lo = 1;
|
||||
|
@ -315,9 +312,9 @@ static int evea_codec_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int evea_codec_suspend(struct snd_soc_codec *codec)
|
||||
static int evea_codec_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
|
||||
evea_set_power_state_off(evea);
|
||||
|
||||
|
@ -331,9 +328,9 @@ static int evea_codec_suspend(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int evea_codec_resume(struct snd_soc_codec *codec)
|
||||
static int evea_codec_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct evea_priv *evea = snd_soc_codec_get_drvdata(codec);
|
||||
struct evea_priv *evea = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(evea->clk);
|
||||
|
@ -376,19 +373,20 @@ err_out_clock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_evea = {
|
||||
.probe = evea_codec_probe,
|
||||
.suspend = evea_codec_suspend,
|
||||
.resume = evea_codec_resume,
|
||||
|
||||
.component_driver = {
|
||||
.dapm_widgets = evea_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(evea_widgets),
|
||||
.dapm_routes = evea_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(evea_routes),
|
||||
.controls = eva_controls,
|
||||
.num_controls = ARRAY_SIZE(eva_controls),
|
||||
},
|
||||
static struct snd_soc_component_driver soc_codec_evea = {
|
||||
.probe = evea_codec_probe,
|
||||
.suspend = evea_codec_suspend,
|
||||
.resume = evea_codec_resume,
|
||||
.dapm_widgets = evea_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(evea_widgets),
|
||||
.dapm_routes = evea_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(evea_routes),
|
||||
.controls = evea_controls,
|
||||
.num_controls = ARRAY_SIZE(evea_controls),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver soc_dai_evea[] = {
|
||||
|
@ -505,7 +503,7 @@ static int evea_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, evea);
|
||||
|
||||
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_evea,
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_evea,
|
||||
soc_dai_evea, ARRAY_SIZE(soc_dai_evea));
|
||||
if (ret)
|
||||
goto err_out_reset_adamv;
|
||||
|
@ -534,8 +532,6 @@ static int evea_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct evea_priv *evea = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
reset_control_assert(evea->rst_adamv);
|
||||
reset_control_assert(evea->rst_exiv);
|
||||
reset_control_assert(evea->rst);
|
||||
|
|
Загрузка…
Ссылка в новой задаче