Commit cb6bfd3d authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/rx51', 'asoc/topic/samsung',...

Merge remote-tracking branches 'asoc/topic/rx51', 'asoc/topic/samsung', 'asoc/topic/sh', 'asoc/topic/simple' and 'asoc/topic/sta32x' into asoc-next
...@@ -33,6 +33,25 @@ Required SoC Specific Properties: ...@@ -33,6 +33,25 @@ Required SoC Specific Properties:
"iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2 clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
doesn't have any such mux. doesn't have any such mux.
- #clock-cells: should be 1, this property must be present if the I2S device
is a clock provider in terms of the common clock bindings, described in
../clock/clock-bindings.txt.
- clock-output-names: from the common clock bindings, names of the CDCLK
I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
"i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
There are following clocks available at the I2S device nodes:
CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock,
CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
IISPSR register),
CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
IISMOD register).
Refer to the SoC datasheet for availability of the above clocks.
The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
in the IIS Multi Audio Interface (I2S0).
Note: Old DTs may not have the #clock-cells, clock-output-names properties
and then not use the I2S node as a clock supplier.
Optional SoC Specific Properties: Optional SoC Specific Properties:
...@@ -41,6 +60,7 @@ Optional SoC Specific Properties: ...@@ -41,6 +60,7 @@ Optional SoC Specific Properties:
- pinctrl-0: Should specify pin control groups used for this controller. - pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default". - pinctrl-names: Should contain only one value - "default".
Example: Example:
i2s0: i2s@03830000 { i2s0: i2s@03830000 {
...@@ -54,6 +74,8 @@ i2s0: i2s@03830000 { ...@@ -54,6 +74,8 @@ i2s0: i2s@03830000 {
<&clock_audss EXYNOS_I2S_BUS>, <&clock_audss EXYNOS_I2S_BUS>,
<&clock_audss EXYNOS_SCLK_I2S>; <&clock_audss EXYNOS_SCLK_I2S>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
#clock-cells;
clock-output-names = "i2s_cdclk0";
samsung,idma-addr = <0x03000000>; samsung,idma-addr = <0x03000000>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>; pinctrl-0 = <&i2s0_bus>;
......
...@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties: ...@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties:
it can be specified via "clocks" if system has it can be specified via "clocks" if system has
clock node (= common clock), or "system-clock-frequency" clock node (= common clock), or "system-clock-frequency"
(if system doens't support common clock) (if system doens't support common clock)
If a clock is specified, it is
enabled with clk_prepare_enable()
in dai startup() and disabled with
clk_disable_unprepare() in dai
shutdown().
Example 1 - single DAI link: Example 1 - single DAI link:
......
STA32X audio CODEC
The driver for this device only supports I2C.
Required properties:
- compatible: "st,sta32x"
- reg: the I2C address of the device for I2C
- reset-gpios: a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the codec starts.
- power-down-gpios: a GPIO spec for the power down pin. If specified,
it will be deasserted before communication to the codec
starts.
- Vdda-supply: regulator spec, providing 3.3V
- Vdd3-supply: regulator spec, providing 3.3V
- Vcc-supply: regulator spec, providing 5V - 26V
Optional properties:
- st,output-conf: number, Selects the output configuration:
0: 2-channel (full-bridge) power, 2-channel data-out
1: 2 (half-bridge). 1 (full-bridge) on-board power
2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
3: 1 Channel Mono-Parallel
If parameter is missing, mode 0 will be enabled.
This property has to be specified as '/bits/ 8' value.
- st,ch1-output-mapping: Channel 1 output mapping
- st,ch2-output-mapping: Channel 2 output mapping
- st,ch3-output-mapping: Channel 3 output mapping
0: Channel 1
1: Channel 2
2: Channel 3
If parameter is missing, channel 1 is chosen.
This properties have to be specified as '/bits/ 8' values.
- st,thermal-warning-recover:
If present, thermal warning recovery is enabled.
- st,thermal-warning-adjustment:
If present, thermal warning adjustment is enabled.
- st,fault-detect-recovery:
If present, then fault recovery will be enabled.
- st,drop-compensation-ns: number
Only required for "st,ffx-power-output-mode" ==
"variable-drop-compensation".
Specifies the drop compensation in nanoseconds.
The value must be in the range of 0..300, and only
multiples of 20 are allowed. Default is 140ns.
- st,max-power-use-mpcc:
If present, then MPCC bits are used for MPC coefficients,
otherwise standard MPC coefficients are used.
- st,max-power-corr:
If present, power bridge correction for THD reduction near maximum
power output is enabled.
- st,am-reduction-mode:
If present, FFX mode runs in AM reduction mode, otherwise normal
FFX mode is used.
- st,odd-pwm-speed-mode:
If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
channels. If not present, normal PWM spped mode (384 kHz) will be used.
- st,invalid-input-detect-mute:
If present, automatic invalid input detect mute is enabled.
Example:
codec: sta32x@38 {
compatible = "st,sta32x";
reg = <0x1c>;
reset-gpios = <&gpio1 19 0>;
power-down-gpios = <&gpio1 16 0>;
st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
// (full-bridge) power,
// 2-channel data-out
st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1
st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1
st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1
st,max-power-correction; // enables power bridge
// correction for THD reduction
// near maximum power output
st,invalid-input-detect-mute; // mute if no valid digital
// audio signal is provided.
};
#ifndef _DT_BINDINGS_SAMSUNG_I2S_H
#define _DT_BINDINGS_SAMSUNG_I2S_H
#define CLK_I2S_CDCLK 0
#define CLK_I2S_RCLK_SRC 1
#define CLK_I2S_RCLK_PSR 2
#endif /* _DT_BINDINGS_SAMSUNG_I2S_H */
...@@ -20,6 +20,7 @@ struct asoc_simple_dai { ...@@ -20,6 +20,7 @@ struct asoc_simple_dai {
unsigned int sysclk; unsigned int sysclk;
int slots; int slots;
int slot_width; int slot_width;
struct clk *clk;
}; };
struct asoc_simple_card_info { struct asoc_simple_card_info {
......
...@@ -24,12 +24,20 @@ ...@@ -24,12 +24,20 @@
#define STA32X_THERMAL_RECOVERY_ENABLE 2 #define STA32X_THERMAL_RECOVERY_ENABLE 2
struct sta32x_platform_data { struct sta32x_platform_data {
int output_conf; u8 output_conf;
int ch1_output_mapping; u8 ch1_output_mapping;
int ch2_output_mapping; u8 ch2_output_mapping;
int ch3_output_mapping; u8 ch3_output_mapping;
int thermal_conf;
int needs_esd_watchdog; int needs_esd_watchdog;
u8 drop_compensation_ns;
unsigned int thermal_warning_recovery:1;
unsigned int thermal_warning_adjustment:1;
unsigned int fault_detect_recovery:1;
unsigned int max_power_use_mpcc:1;
unsigned int max_power_correction:1;
unsigned int am_reduction_mode:1;
unsigned int odd_pwm_speed_mode:1;
unsigned int invalid_input_detect_mute:1;
}; };
#endif /* __LINUX_SND__STA32X_H */ #endif /* __LINUX_SND__STA32X_H */
...@@ -580,7 +580,9 @@ config SND_SOC_SSM4567 ...@@ -580,7 +580,9 @@ config SND_SOC_SSM4567
depends on I2C depends on I2C
config SND_SOC_STA32X config SND_SOC_STA32X
tristate tristate "STA326, STA328 and STA329 speaker amplifier"
depends on I2C
select REGMAP_I2C
config SND_SOC_STA350 config SND_SOC_STA350
tristate "STA350 speaker amplifier" tristate "STA350 speaker amplifier"
......
This diff is collapsed.
...@@ -39,6 +39,37 @@ struct simple_card_data { ...@@ -39,6 +39,37 @@ struct simple_card_data {
#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
#define simple_priv_to_props(priv, i) ((priv)->dai_props + i) #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
&priv->dai_props[rtd - rtd->card->rtd];
int ret;
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
if (ret)
return ret;
ret = clk_prepare_enable(dai_props->codec_dai.clk);
if (ret)
clk_disable_unprepare(dai_props->cpu_dai.clk);
return ret;
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
&priv->dai_props[rtd - rtd->card->rtd];
clk_disable_unprepare(dai_props->cpu_dai.clk);
clk_disable_unprepare(dai_props->codec_dai.clk);
}
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -58,6 +89,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, ...@@ -58,6 +89,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
} }
static struct snd_soc_ops asoc_simple_card_ops = { static struct snd_soc_ops asoc_simple_card_ops = {
.startup = asoc_simple_card_startup,
.shutdown = asoc_simple_card_shutdown,
.hw_params = asoc_simple_card_hw_params, .hw_params = asoc_simple_card_hw_params,
}; };
...@@ -219,6 +252,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, ...@@ -219,6 +252,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
} }
dai->sysclk = clk_get_rate(clk); dai->sysclk = clk_get_rate(clk);
dai->clk = clk;
} else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
dai->sysclk = val; dai->sysclk = val;
} else { } else {
......
...@@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = { ...@@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "LLOUT"},
{"FM Transmitter", NULL, "RLOUT"}, {"FM Transmitter", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias"}, {"DMic Rate 64", NULL, "DMic"},
{"Mic Bias", NULL, "DMic"}, {"DMic", NULL, "Mic Bias"},
{"b LINE2R", NULL, "MONO_LOUT"}, {"b LINE2R", NULL, "MONO_LOUT"},
{"Earphone", NULL, "b HPLOUT"}, {"Earphone", NULL, "b HPLOUT"},
{"LINE1L", NULL, "b Mic Bias"}, {"LINE1L", NULL, "HS Mic"},
{"b Mic Bias", NULL, "HS Mic"} {"HS Mic", NULL, "b Mic Bias"},
}; };
static const char * const spk_function[] = {"Off", "On"}; static const char * const spk_function[] = {"Off", "On"};
......
...@@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 ...@@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK" tristate "SoC I2S Audio support for WM8580 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
depends on REGMAP_I2C depends on I2C
select SND_SOC_WM8580 select SND_SOC_WM8580
select SND_SAMSUNG_I2S select SND_SAMSUNG_I2S
help help
...@@ -167,7 +167,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF ...@@ -167,7 +167,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
config SND_SOC_SMDK_WM8580_PCM config SND_SOC_SMDK_WM8580_PCM
tristate "SoC PCM Audio support for WM8580 on SMDK" tristate "SoC PCM Audio support for WM8580 on SMDK"
depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110) depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110)
depends on REGMAP_I2C depends on I2C
select SND_SOC_WM8580 select SND_SOC_WM8580
select SND_SAMSUNG_PCM select SND_SAMSUNG_PCM
help help
......
...@@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); ...@@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
static struct platform_driver arndale_audio_driver = { static struct platform_driver arndale_audio_driver = {
.driver = { .driver = {
.name = "arndale-audio", .name = "arndale-audio",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
.of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
}, },
......
This diff is collapsed.
...@@ -83,22 +83,6 @@ static struct snd_soc_ops jive_ops = { ...@@ -83,22 +83,6 @@ static struct snd_soc_ops jive_ops = {
.hw_params = jive_hw_params, .hw_params = jive_hw_params,
}; };
static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* These endpoints are not being used. */
snd_soc_dapm_nc_pin(dapm, "LINPUT2");
snd_soc_dapm_nc_pin(dapm, "RINPUT2");
snd_soc_dapm_nc_pin(dapm, "LINPUT3");
snd_soc_dapm_nc_pin(dapm, "RINPUT3");
snd_soc_dapm_nc_pin(dapm, "OUT3");
snd_soc_dapm_nc_pin(dapm, "MONO");
return 0;
}
static struct snd_soc_dai_link jive_dai = { static struct snd_soc_dai_link jive_dai = {
.name = "wm8750", .name = "wm8750",
.stream_name = "WM8750", .stream_name = "WM8750",
...@@ -106,7 +90,6 @@ static struct snd_soc_dai_link jive_dai = { ...@@ -106,7 +90,6 @@ static struct snd_soc_dai_link jive_dai = {
.codec_dai_name = "wm8750-hifi", .codec_dai_name = "wm8750-hifi",
.platform_name = "s3c2412-i2s", .platform_name = "s3c2412-i2s",
.codec_name = "wm8750.0-001a", .codec_name = "wm8750.0-001a",
.init = jive_wm8750_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAIFMT_CBS_CFS,
.ops = &jive_ops, .ops = &jive_ops,
...@@ -123,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = { ...@@ -123,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = {
.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
.dapm_routes = audio_map, .dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map), .num_dapm_routes = ARRAY_SIZE(audio_map),
.fully_routed = true,
}; };
static struct platform_device *jive_snd_device; static struct platform_device *jive_snd_device;
......
...@@ -21,6 +21,8 @@ struct odroidx2_drv_data { ...@@ -21,6 +21,8 @@ struct odroidx2_drv_data {
/* The I2S CDCLK output clock frequency for the MAX98090 codec */ /* The I2S CDCLK output clock frequency for the MAX98090 codec */
#define MAX98090_MCLK 19200000 #define MAX98090_MCLK 19200000
static struct snd_soc_dai_link odroidx2_dai[];
static int odroidx2_late_probe(struct snd_soc_card *card) static int odroidx2_late_probe(struct snd_soc_card *card)
{ {
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
...@@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card) ...@@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card)
ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
SND_SOC_CLOCK_IN); SND_SOC_CLOCK_IN);
if (ret < 0)
if (ret < 0 || of_find_property(odroidx2_dai[0].codec_of_node,
"clocks", NULL))
return ret; return ret;
/* Set the cpu DAI configuration in order to use CDCLK */ /* Set the cpu DAI configuration in order to use CDCLK */
......
...@@ -136,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = { ...@@ -136,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* Enabling the microphone requires the fitting of a 0R /* Enabling the microphone requires the fitting of a 0R
* resistor to connect the line from the microphone jack. * resistor to connect the line from the microphone jack.
*/ */
snd_soc_dapm_disable_pin(dapm, "MicIn"); snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn");
return 0; return 0;
} }
......
...@@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = { ...@@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = {
.pointer = camelot_pos, .pointer = camelot_pos,
}; };
static void camelot_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_pcm *pcm = rtd->pcm; struct snd_pcm *pcm = rtd->pcm;
...@@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_platform_driver sh7760_soc_platform = { static struct snd_soc_platform_driver sh7760_soc_platform = {
.ops = &camelot_pcm_ops, .ops = &camelot_pcm_ops,
.pcm_new = camelot_pcm_new, .pcm_new = camelot_pcm_new,
.pcm_free = camelot_pcm_free,
}; };
static int sh7760_soc_platform_probe(struct platform_device *pdev) static int sh7760_soc_platform_probe(struct platform_device *pdev)
......
...@@ -1762,11 +1762,6 @@ static struct snd_pcm_ops fsi_pcm_ops = { ...@@ -1762,11 +1762,6 @@ static struct snd_pcm_ops fsi_pcm_ops = {
#define PREALLOC_BUFFER (32 * 1024) #define PREALLOC_BUFFER (32 * 1024)
#define PREALLOC_BUFFER_MAX (32 * 1024) #define PREALLOC_BUFFER_MAX (32 * 1024)
static void fsi_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
{ {
return snd_pcm_lib_preallocate_pages_for_all( return snd_pcm_lib_preallocate_pages_for_all(
...@@ -1818,7 +1813,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = { ...@@ -1818,7 +1813,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
static struct snd_soc_platform_driver fsi_soc_platform = { static struct snd_soc_platform_driver fsi_soc_platform = {
.ops = &fsi_pcm_ops, .ops = &fsi_pcm_ops,
.pcm_new = fsi_pcm_new, .pcm_new = fsi_pcm_new,
.pcm_free = fsi_pcm_free,
}; };
static const struct snd_soc_component_driver fsi_soc_component = { static const struct snd_soc_component_driver fsi_soc_component = {
......
...@@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm) ...@@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm)
tasklet_kill(&port_info->playback.tasklet); tasklet_kill(&port_info->playback.tasklet);
siu_free_port(port_info); siu_free_port(port_info);
snd_pcm_lib_preallocate_free_for_all(pcm);
dev_dbg(pcm->card->dev, "%s\n", __func__); dev_dbg(pcm->card->dev, "%s\n", __func__);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment