Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d7e3281b
Commit
d7e3281b
authored
Mar 05, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/wm8804' into asoc-next
parents
3a948636
6f2c9348
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
225 additions
and
205 deletions
+225
-205
sound/soc/codecs/Kconfig
sound/soc/codecs/Kconfig
+15
-3
sound/soc/codecs/Makefile
sound/soc/codecs/Makefile
+4
-0
sound/soc/codecs/wm8804-i2c.c
sound/soc/codecs/wm8804-i2c.c
+64
-0
sound/soc/codecs/wm8804-spi.c
sound/soc/codecs/wm8804-spi.c
+56
-0
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8804.c
+79
-202
sound/soc/codecs/wm8804.h
sound/soc/codecs/wm8804.h
+7
-0
No files found.
sound/soc/codecs/Kconfig
View file @
d7e3281b
...
...
@@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8770 if SPI_MASTER
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8782
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8804_I2C if I2C
select SND_SOC_WM8804_SPI if SPI_MASTER
select SND_SOC_WM8900 if I2C
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8904 if I2C
...
...
@@ -744,8 +745,19 @@ config SND_SOC_WM8782
tristate
config SND_SOC_WM8804
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
depends on SND_SOC_I2C_AND_SPI
tristate
config SND_SOC_WM8804_I2C
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C"
depends on I2C
select SND_SOC_WM8804
select REGMAP_I2C
config SND_SOC_WM8804_SPI
tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI"
depends on SPI_MASTER
select SND_SOC_WM8804
select REGMAP_SPI
config SND_SOC_WM8900
tristate
...
...
sound/soc/codecs/Makefile
View file @
d7e3281b
...
...
@@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o
snd-soc-wm8776-objs
:=
wm8776.o
snd-soc-wm8782-objs
:=
wm8782.o
snd-soc-wm8804-objs
:=
wm8804.o
snd-soc-wm8804-i2c-objs
:=
wm8804-i2c.o
snd-soc-wm8804-spi-objs
:=
wm8804-spi.o
snd-soc-wm8900-objs
:=
wm8900.o
snd-soc-wm8903-objs
:=
wm8903.o
snd-soc-wm8904-objs
:=
wm8904.o
...
...
@@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o
obj-$(CONFIG_SND_SOC_WM8776)
+=
snd-soc-wm8776.o
obj-$(CONFIG_SND_SOC_WM8782)
+=
snd-soc-wm8782.o
obj-$(CONFIG_SND_SOC_WM8804)
+=
snd-soc-wm8804.o
obj-$(CONFIG_SND_SOC_WM8804_I2C)
+=
snd-soc-wm8804-i2c.o
obj-$(CONFIG_SND_SOC_WM8804_SPI)
+=
snd-soc-wm8804-spi.o
obj-$(CONFIG_SND_SOC_WM8900)
+=
snd-soc-wm8900.o
obj-$(CONFIG_SND_SOC_WM8903)
+=
snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8904)
+=
snd-soc-wm8904.o
...
...
sound/soc/codecs/wm8804-i2c.c
0 → 100644
View file @
d7e3281b
/*
* wm8804-i2c.c -- WM8804 S/PDIF transceiver driver - I2C
*
* Copyright 2015 Cirrus Logic Inc
*
* Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include "wm8804.h"
static
int
wm8804_i2c_probe
(
struct
i2c_client
*
i2c
,
const
struct
i2c_device_id
*
id
)
{
struct
regmap
*
regmap
;
regmap
=
devm_regmap_init_i2c
(
i2c
,
&
wm8804_regmap_config
);
if
(
IS_ERR
(
regmap
))
return
PTR_ERR
(
regmap
);
return
wm8804_probe
(
&
i2c
->
dev
,
regmap
);
}
static
int
wm8804_i2c_remove
(
struct
i2c_client
*
i2c
)
{
wm8804_remove
(
&
i2c
->
dev
);
return
0
;
}
static
const
struct
i2c_device_id
wm8804_i2c_id
[]
=
{
{
"wm8804"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
wm8804_i2c_id
);
static
const
struct
of_device_id
wm8804_of_match
[]
=
{
{
.
compatible
=
"wlf,wm8804"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
wm8804_of_match
);
static
struct
i2c_driver
wm8804_i2c_driver
=
{
.
driver
=
{
.
name
=
"wm8804"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
wm8804_of_match
,
},
.
probe
=
wm8804_i2c_probe
,
.
remove
=
wm8804_i2c_remove
,
.
id_table
=
wm8804_i2c_id
};
module_i2c_driver
(
wm8804_i2c_driver
);
MODULE_DESCRIPTION
(
"ASoC WM8804 driver - I2C"
);
MODULE_AUTHOR
(
"Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/codecs/wm8804-spi.c
0 → 100644
View file @
d7e3281b
/*
* wm8804-spi.c -- WM8804 S/PDIF transceiver driver - SPI
*
* Copyright 2015 Cirrus Logic Inc
*
* Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include "wm8804.h"
static
int
wm8804_spi_probe
(
struct
spi_device
*
spi
)
{
struct
regmap
*
regmap
;
regmap
=
devm_regmap_init_spi
(
spi
,
&
wm8804_regmap_config
);
if
(
IS_ERR
(
regmap
))
return
PTR_ERR
(
regmap
);
return
wm8804_probe
(
&
spi
->
dev
,
regmap
);
}
static
int
wm8804_spi_remove
(
struct
spi_device
*
spi
)
{
wm8804_remove
(
&
spi
->
dev
);
return
0
;
}
static
const
struct
of_device_id
wm8804_of_match
[]
=
{
{
.
compatible
=
"wlf,wm8804"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
wm8804_of_match
);
static
struct
spi_driver
wm8804_spi_driver
=
{
.
driver
=
{
.
name
=
"wm8804"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
wm8804_of_match
,
},
.
probe
=
wm8804_spi_probe
,
.
remove
=
wm8804_spi_remove
};
module_spi_driver
(
wm8804_spi_driver
);
MODULE_DESCRIPTION
(
"ASoC WM8804 driver - SPI"
);
MODULE_AUTHOR
(
"Charles Keepax <ckeepax@opensource.wolfsonmicro.com>"
);
MODULE_LICENSE
(
"GPL"
);
sound/soc/codecs/wm8804.c
View file @
d7e3281b
...
...
@@ -15,10 +15,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
...
...
@@ -185,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg)
}
}
static
int
wm8804_reset
(
struct
snd_soc_codec
*
codec
)
static
int
wm8804_reset
(
struct
wm8804_priv
*
wm8804
)
{
return
snd_soc_write
(
codec
,
WM8804_RST_DEVID1
,
0x0
);
return
regmap_write
(
wm8804
->
regmap
,
WM8804_RST_DEVID1
,
0x0
);
}
static
int
wm8804_set_fmt
(
struct
snd_soc_dai
*
dai
,
unsigned
int
fmt
)
...
...
@@ -518,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
return
0
;
}
static
int
wm8804_remove
(
struct
snd_soc_codec
*
codec
)
{
struct
wm8804_priv
*
wm8804
;
int
i
;
wm8804
=
snd_soc_codec_get_drvdata
(
codec
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8804
->
supplies
);
++
i
)
regulator_unregister_notifier
(
wm8804
->
supplies
[
i
].
consumer
,
&
wm8804
->
disable_nb
[
i
]);
return
0
;
}
static
int
wm8804_probe
(
struct
snd_soc_codec
*
codec
)
{
struct
wm8804_priv
*
wm8804
;
int
i
,
id1
,
id2
,
ret
;
wm8804
=
snd_soc_codec_get_drvdata
(
codec
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8804
->
supplies
);
i
++
)
wm8804
->
supplies
[
i
].
supply
=
wm8804_supply_names
[
i
];
ret
=
devm_regulator_bulk_get
(
codec
->
dev
,
ARRAY_SIZE
(
wm8804
->
supplies
),
wm8804
->
supplies
);
if
(
ret
)
{
dev_err
(
codec
->
dev
,
"Failed to request supplies: %d
\n
"
,
ret
);
return
ret
;
}
wm8804
->
disable_nb
[
0
].
notifier_call
=
wm8804_regulator_event_0
;
wm8804
->
disable_nb
[
1
].
notifier_call
=
wm8804_regulator_event_1
;
/* This should really be moved into the regulator core */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8804
->
supplies
);
i
++
)
{
ret
=
regulator_register_notifier
(
wm8804
->
supplies
[
i
].
consumer
,
&
wm8804
->
disable_nb
[
i
]);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to register regulator notifier: %d
\n
"
,
ret
);
}
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm8804
->
supplies
),
wm8804
->
supplies
);
if
(
ret
)
{
dev_err
(
codec
->
dev
,
"Failed to enable supplies: %d
\n
"
,
ret
);
return
ret
;
}
id1
=
snd_soc_read
(
codec
,
WM8804_RST_DEVID1
);
if
(
id1
<
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read device ID: %d
\n
"
,
id1
);
ret
=
id1
;
goto
err_reg_enable
;
}
id2
=
snd_soc_read
(
codec
,
WM8804_DEVID2
);
if
(
id2
<
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read device ID: %d
\n
"
,
id2
);
ret
=
id2
;
goto
err_reg_enable
;
}
id2
=
(
id2
<<
8
)
|
id1
;
if
(
id2
!=
0x8805
)
{
dev_err
(
codec
->
dev
,
"Invalid device ID: %#x
\n
"
,
id2
);
ret
=
-
EINVAL
;
goto
err_reg_enable
;
}
ret
=
snd_soc_read
(
codec
,
WM8804_DEVREV
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"Failed to read device revision: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
dev_info
(
codec
->
dev
,
"revision %c
\n
"
,
ret
+
'A'
);
ret
=
wm8804_reset
(
codec
);
if
(
ret
<
0
)
{
dev_err
(
codec
->
dev
,
"Failed to issue reset: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
return
0
;
err_reg_enable:
regulator_bulk_disable
(
ARRAY_SIZE
(
wm8804
->
supplies
),
wm8804
->
supplies
);
return
ret
;
}
static
const
struct
snd_soc_dai_ops
wm8804_dai_ops
=
{
.
hw_params
=
wm8804_hw_params
,
.
set_fmt
=
wm8804_set_fmt
,
...
...
@@ -649,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = {
};
static
const
struct
snd_soc_codec_driver
soc_codec_dev_wm8804
=
{
.
probe
=
wm8804_probe
,
.
remove
=
wm8804_remove
,
.
set_bias_level
=
wm8804_set_bias_level
,
.
idle_bias_off
=
true
,
...
...
@@ -658,13 +559,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
.
num_controls
=
ARRAY_SIZE
(
wm8804_snd_controls
),
};
static
const
struct
of_device_id
wm8804_of_match
[]
=
{
{
.
compatible
=
"wlf,wm8804"
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
wm8804_of_match
);
static
const
struct
regmap_config
wm8804_regmap_config
=
{
const
struct
regmap_config
wm8804_regmap_config
=
{
.
reg_bits
=
8
,
.
val_bits
=
8
,
...
...
@@ -675,128 +570,110 @@ static const struct regmap_config wm8804_regmap_config = {
.
reg_defaults
=
wm8804_reg_defaults
,
.
num_reg_defaults
=
ARRAY_SIZE
(
wm8804_reg_defaults
),
};
EXPORT_SYMBOL_GPL
(
wm8804_regmap_config
);
#if defined(CONFIG_SPI_MASTER)
static
int
wm8804_spi_probe
(
struct
spi_device
*
spi
)
int
wm8804_probe
(
struct
device
*
dev
,
struct
regmap
*
regmap
)
{
struct
wm8804_priv
*
wm8804
;
int
ret
;
unsigned
int
id1
,
id2
;
int
i
,
ret
;
wm8804
=
devm_kzalloc
(
&
spi
->
dev
,
sizeof
*
wm8804
,
GFP_KERNEL
);
wm8804
=
devm_kzalloc
(
dev
,
sizeof
(
*
wm8804
)
,
GFP_KERNEL
);
if
(
!
wm8804
)
return
-
ENOMEM
;
wm8804
->
regmap
=
devm_regmap_init_spi
(
spi
,
&
wm8804_regmap_config
);
if
(
IS_ERR
(
wm8804
->
regmap
))
{
ret
=
PTR_ERR
(
wm8804
->
regmap
);
dev_set_drvdata
(
dev
,
wm8804
);
wm8804
->
regmap
=
regmap
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8804
->
supplies
);
i
++
)
wm8804
->
supplies
[
i
].
supply
=
wm8804_supply_names
[
i
];
ret
=
devm_regulator_bulk_get
(
dev
,
ARRAY_SIZE
(
wm8804
->
supplies
),
wm8804
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to request supplies: %d
\n
"
,
ret
);
return
ret
;
}
spi_set_drvdata
(
spi
,
wm8804
);
wm8804
->
disable_nb
[
0
].
notifier_call
=
wm8804_regulator_event_0
;
wm8804
->
disable_nb
[
1
].
notifier_call
=
wm8804_regulator_event_1
;
ret
=
snd_soc_register_codec
(
&
spi
->
dev
,
&
soc_codec_dev_wm8804
,
&
wm8804_dai
,
1
);
/* This should really be moved into the regulator core */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8804
->
supplies
);
i
++
)
{
ret
=
regulator_register_notifier
(
wm8804
->
supplies
[
i
].
consumer
,
&
wm8804
->
disable_nb
[
i
]);
if
(
ret
!=
0
)
{
dev_err
(
dev
,
"Failed to register regulator notifier: %d
\n
"
,
ret
);
}
}
return
ret
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm8804
->
supplies
),
wm8804
->
supplies
);
if
(
ret
)
{
dev_err
(
dev
,
"Failed to enable supplies: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
static
int
wm8804_spi_remove
(
struct
spi_device
*
spi
)
{
snd_soc_unregister_codec
(
&
spi
->
dev
);
return
0
;
}
ret
=
regmap_read
(
regmap
,
WM8804_RST_DEVID1
,
&
id1
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Failed to read device ID: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
static
struct
spi_driver
wm8804_spi_driver
=
{
.
driver
=
{
.
name
=
"wm8804"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
wm8804_of_match
,
},
.
probe
=
wm8804_spi_probe
,
.
remove
=
wm8804_spi_remove
};
#endif
ret
=
regmap_read
(
regmap
,
WM8804_DEVID2
,
&
id2
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Failed to read device ID: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
#if IS_ENABLED(CONFIG_I2C)
static
int
wm8804_i2c_probe
(
struct
i2c_client
*
i2c
,
const
struct
i2c_device_id
*
id
)
{
struct
wm8804_priv
*
wm8804
;
int
ret
;
id2
=
(
id2
<<
8
)
|
id1
;
wm8804
=
devm_kzalloc
(
&
i2c
->
dev
,
sizeof
*
wm8804
,
GFP_KERNEL
);
if
(
!
wm8804
)
return
-
ENOMEM
;
if
(
id2
!=
0x8805
)
{
dev_err
(
dev
,
"Invalid device ID: %#x
\n
"
,
id2
);
ret
=
-
EINVAL
;
goto
err_reg_enable
;
}
wm8804
->
regmap
=
devm_regmap_init_i2c
(
i2c
,
&
wm8804_regmap_config
);
if
(
IS_ERR
(
wm8804
->
regmap
))
{
ret
=
PTR_ERR
(
wm8804
->
regmap
);
return
ret
;
ret
=
regmap_read
(
regmap
,
WM8804_DEVREV
,
&
id1
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Failed to read device revision: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
dev_info
(
dev
,
"revision %c
\n
"
,
id1
+
'A'
);
i2c_set_clientdata
(
i2c
,
wm8804
);
ret
=
wm8804_reset
(
wm8804
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Failed to issue reset: %d
\n
"
,
ret
);
goto
err_reg_enable
;
}
ret
=
snd_soc_register_codec
(
&
i2c
->
dev
,
&
soc_codec_dev_wm8804
,
&
wm8804_dai
,
1
);
return
snd_soc_register_codec
(
dev
,
&
soc_codec_dev_wm8804
,
&
wm8804_dai
,
1
);
err_reg_enable:
regulator_bulk_disable
(
ARRAY_SIZE
(
wm8804
->
supplies
),
wm8804
->
supplies
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
wm8804_probe
);
static
int
wm8804_i2c_remove
(
struct
i2c_client
*
i2c
)
void
wm8804_remove
(
struct
device
*
dev
)
{
snd_soc_unregister_codec
(
&
i2c
->
dev
);
return
0
;
}
static
const
struct
i2c_device_id
wm8804_i2c_id
[]
=
{
{
"wm8804"
,
0
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
wm8804_i2c_id
);
static
struct
i2c_driver
wm8804_i2c_driver
=
{
.
driver
=
{
.
name
=
"wm8804"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
wm8804_of_match
,
},
.
probe
=
wm8804_i2c_probe
,
.
remove
=
wm8804_i2c_remove
,
.
id_table
=
wm8804_i2c_id
};
#endif
struct
wm8804_priv
*
wm8804
;
int
i
;
static
int
__init
wm8804_modinit
(
void
)
{
int
ret
=
0
;
wm8804
=
dev_get_drvdata
(
dev
);
#if IS_ENABLED(CONFIG_I2C)
ret
=
i2c_add_driver
(
&
wm8804_i2c_driver
);
if
(
ret
)
{
printk
(
KERN_ERR
"Failed to register wm8804 I2C driver: %d
\n
"
,
ret
);
}
#endif
#if defined(CONFIG_SPI_MASTER)
ret
=
spi_register_driver
(
&
wm8804_spi_driver
);
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
"Failed to register wm8804 SPI driver: %d
\n
"
,
ret
);
}
#endif
return
ret
;
}
module_init
(
wm8804_modinit
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wm8804
->
supplies
);
++
i
)
regulator_unregister_notifier
(
wm8804
->
supplies
[
i
].
consumer
,
&
wm8804
->
disable_nb
[
i
]);
static
void
__exit
wm8804_exit
(
void
)
{
#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver
(
&
wm8804_i2c_driver
);
#endif
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver
(
&
wm8804_spi_driver
);
#endif
snd_soc_unregister_codec
(
dev
);
}
module_exit
(
wm8804_exit
);
EXPORT_SYMBOL_GPL
(
wm8804_remove
);
MODULE_DESCRIPTION
(
"ASoC WM8804 driver"
);
MODULE_AUTHOR
(
"Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"
);
...
...
sound/soc/codecs/wm8804.h
View file @
d7e3281b
...
...
@@ -13,6 +13,8 @@
#ifndef _WM8804_H
#define _WM8804_H
#include <linux/regmap.h>
/*
* Register values.
*/
...
...
@@ -62,4 +64,9 @@
#define WM8804_MCLKDIV_256FS 0
#define WM8804_MCLKDIV_128FS 1
extern
const
struct
regmap_config
wm8804_regmap_config
;
int
wm8804_probe
(
struct
device
*
dev
,
struct
regmap
*
regmap
);
void
wm8804_remove
(
struct
device
*
dev
);
#endif
/* _WM8804_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment