|
@@ -30,6 +30,7 @@
|
|
|
#include <linux/of_platform.h>
|
|
|
#include <linux/clk.h>
|
|
|
#include <linux/regmap.h>
|
|
|
+#include <linux/reset.h>
|
|
|
#include <linux/gpio/consumer.h>
|
|
|
|
|
|
#include <sound/core.h>
|
|
@@ -217,6 +218,7 @@ struct sun4i_codec {
|
|
|
struct regmap *regmap;
|
|
|
struct clk *clk_apb;
|
|
|
struct clk *clk_module;
|
|
|
+ struct reset_control *rst;
|
|
|
struct gpio_desc *gpio_pa;
|
|
|
|
|
|
/* ADC_FIFOC register is at different offset on different SoCs */
|
|
@@ -1232,6 +1234,7 @@ struct sun4i_codec_quirks {
|
|
|
struct reg_field reg_adc_fifoc; /* used for regmap_field */
|
|
|
unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
|
|
|
unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
|
|
|
+ bool has_reset;
|
|
|
};
|
|
|
|
|
|
static const struct sun4i_codec_quirks sun4i_codec_quirks = {
|
|
@@ -1327,6 +1330,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)
|
|
|
return PTR_ERR(scodec->clk_module);
|
|
|
}
|
|
|
|
|
|
+ if (quirks->has_reset) {
|
|
|
+ scodec->rst = devm_reset_control_get(&pdev->dev, NULL);
|
|
|
+ if (IS_ERR(scodec->rst)) {
|
|
|
+ dev_err(&pdev->dev, "Failed to get reset control\n");
|
|
|
+ return PTR_ERR(scodec->rst);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
|
|
|
GPIOD_OUT_LOW);
|
|
|
if (IS_ERR(scodec->gpio_pa)) {
|
|
@@ -1353,6 +1364,16 @@ static int sun4i_codec_probe(struct platform_device *pdev)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ /* Deassert the reset control */
|
|
|
+ if (scodec->rst) {
|
|
|
+ ret = reset_control_deassert(scodec->rst);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(&pdev->dev,
|
|
|
+ "Failed to deassert the reset control\n");
|
|
|
+ goto err_clk_disable;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* DMA configuration for TX FIFO */
|
|
|
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
|
|
|
scodec->playback_dma_data.maxburst = 8;
|
|
@@ -1367,7 +1388,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
|
|
|
&sun4i_codec_dai, 1);
|
|
|
if (ret) {
|
|
|
dev_err(&pdev->dev, "Failed to register our codec\n");
|
|
|
- goto err_clk_disable;
|
|
|
+ goto err_assert_reset;
|
|
|
}
|
|
|
|
|
|
ret = devm_snd_soc_register_component(&pdev->dev,
|
|
@@ -1404,6 +1425,9 @@ static int sun4i_codec_probe(struct platform_device *pdev)
|
|
|
|
|
|
err_unregister_codec:
|
|
|
snd_soc_unregister_codec(&pdev->dev);
|
|
|
+err_assert_reset:
|
|
|
+ if (scodec->rst)
|
|
|
+ reset_control_assert(scodec->rst);
|
|
|
err_clk_disable:
|
|
|
clk_disable_unprepare(scodec->clk_apb);
|
|
|
return ret;
|
|
@@ -1416,6 +1440,8 @@ static int sun4i_codec_remove(struct platform_device *pdev)
|
|
|
|
|
|
snd_soc_unregister_card(card);
|
|
|
snd_soc_unregister_codec(&pdev->dev);
|
|
|
+ if (scodec->rst)
|
|
|
+ reset_control_assert(scodec->rst);
|
|
|
clk_disable_unprepare(scodec->clk_apb);
|
|
|
|
|
|
return 0;
|