diff options
-rw-r--r-- | sound/soc/sunxi/sun4i-codec.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 735115244b17..6379efd21f00 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/of_platform.h> | 30 | #include <linux/of_platform.h> |
31 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
32 | #include <linux/regmap.h> | 32 | #include <linux/regmap.h> |
33 | #include <linux/reset.h> | ||
33 | #include <linux/gpio/consumer.h> | 34 | #include <linux/gpio/consumer.h> |
34 | 35 | ||
35 | #include <sound/core.h> | 36 | #include <sound/core.h> |
@@ -217,6 +218,7 @@ struct sun4i_codec { | |||
217 | struct regmap *regmap; | 218 | struct regmap *regmap; |
218 | struct clk *clk_apb; | 219 | struct clk *clk_apb; |
219 | struct clk *clk_module; | 220 | struct clk *clk_module; |
221 | struct reset_control *rst; | ||
220 | struct gpio_desc *gpio_pa; | 222 | struct gpio_desc *gpio_pa; |
221 | 223 | ||
222 | /* ADC_FIFOC register is at different offset on different SoCs */ | 224 | /* ADC_FIFOC register is at different offset on different SoCs */ |
@@ -1232,6 +1234,7 @@ struct sun4i_codec_quirks { | |||
1232 | struct reg_field reg_adc_fifoc; /* used for regmap_field */ | 1234 | struct reg_field reg_adc_fifoc; /* used for regmap_field */ |
1233 | unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ | 1235 | unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ |
1234 | unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ | 1236 | unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ |
1237 | bool has_reset; | ||
1235 | }; | 1238 | }; |
1236 | 1239 | ||
1237 | static const struct sun4i_codec_quirks sun4i_codec_quirks = { | 1240 | static const struct sun4i_codec_quirks sun4i_codec_quirks = { |
@@ -1327,6 +1330,14 @@ static int sun4i_codec_probe(struct platform_device *pdev) | |||
1327 | return PTR_ERR(scodec->clk_module); | 1330 | return PTR_ERR(scodec->clk_module); |
1328 | } | 1331 | } |
1329 | 1332 | ||
1333 | if (quirks->has_reset) { | ||
1334 | scodec->rst = devm_reset_control_get(&pdev->dev, NULL); | ||
1335 | if (IS_ERR(scodec->rst)) { | ||
1336 | dev_err(&pdev->dev, "Failed to get reset control\n"); | ||
1337 | return PTR_ERR(scodec->rst); | ||
1338 | } | ||
1339 | }; | ||
1340 | |||
1330 | scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", | 1341 | scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", |
1331 | GPIOD_OUT_LOW); | 1342 | GPIOD_OUT_LOW); |
1332 | if (IS_ERR(scodec->gpio_pa)) { | 1343 | if (IS_ERR(scodec->gpio_pa)) { |
@@ -1353,6 +1364,16 @@ static int sun4i_codec_probe(struct platform_device *pdev) | |||
1353 | return -EINVAL; | 1364 | return -EINVAL; |
1354 | } | 1365 | } |
1355 | 1366 | ||
1367 | /* Deassert the reset control */ | ||
1368 | if (scodec->rst) { | ||
1369 | ret = reset_control_deassert(scodec->rst); | ||
1370 | if (ret) { | ||
1371 | dev_err(&pdev->dev, | ||
1372 | "Failed to deassert the reset control\n"); | ||
1373 | goto err_clk_disable; | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1356 | /* DMA configuration for TX FIFO */ | 1377 | /* DMA configuration for TX FIFO */ |
1357 | scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; | 1378 | scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; |
1358 | scodec->playback_dma_data.maxburst = 8; | 1379 | scodec->playback_dma_data.maxburst = 8; |
@@ -1367,7 +1388,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) | |||
1367 | &sun4i_codec_dai, 1); | 1388 | &sun4i_codec_dai, 1); |
1368 | if (ret) { | 1389 | if (ret) { |
1369 | dev_err(&pdev->dev, "Failed to register our codec\n"); | 1390 | dev_err(&pdev->dev, "Failed to register our codec\n"); |
1370 | goto err_clk_disable; | 1391 | goto err_assert_reset; |
1371 | } | 1392 | } |
1372 | 1393 | ||
1373 | ret = devm_snd_soc_register_component(&pdev->dev, | 1394 | ret = devm_snd_soc_register_component(&pdev->dev, |
@@ -1404,6 +1425,9 @@ static int sun4i_codec_probe(struct platform_device *pdev) | |||
1404 | 1425 | ||
1405 | err_unregister_codec: | 1426 | err_unregister_codec: |
1406 | snd_soc_unregister_codec(&pdev->dev); | 1427 | snd_soc_unregister_codec(&pdev->dev); |
1428 | err_assert_reset: | ||
1429 | if (scodec->rst) | ||
1430 | reset_control_assert(scodec->rst); | ||
1407 | err_clk_disable: | 1431 | err_clk_disable: |
1408 | clk_disable_unprepare(scodec->clk_apb); | 1432 | clk_disable_unprepare(scodec->clk_apb); |
1409 | return ret; | 1433 | return ret; |
@@ -1416,6 +1440,8 @@ static int sun4i_codec_remove(struct platform_device *pdev) | |||
1416 | 1440 | ||
1417 | snd_soc_unregister_card(card); | 1441 | snd_soc_unregister_card(card); |
1418 | snd_soc_unregister_codec(&pdev->dev); | 1442 | snd_soc_unregister_codec(&pdev->dev); |
1443 | if (scodec->rst) | ||
1444 | reset_control_assert(scodec->rst); | ||
1419 | clk_disable_unprepare(scodec->clk_apb); | 1445 | clk_disable_unprepare(scodec->clk_apb); |
1420 | 1446 | ||
1421 | return 0; | 1447 | return 0; |