pwmdac: pwmdac@100b0000 {
compatible = "sf,pwmdac";
reg = <0x0 0x100b0000 0x0 0x1000>;
- clocks = <&apb0clk>;
+ clocks = <&clkgen JH7110_APB0>,
+ <&clkgen JH7110_PWMDAC_CLK_APB>,
+ <&clkgen JH7110_PWMDAC_CLK_CORE>;
+ clock-names = "apb0", "pwmdac-apb", "pwmdac-core";
+ resets = <&rstgen RSTN_U0_PWMDAC_APB>;
+ reset-names = "rst-apb";
dmas = <&dma 22 1>;
dma-names = "tx";
#sound-dai-cells = <0>;
};
};
- sound_pwmdac: snd-card_pwmdac {
+ sound:snd-card {
compatible = "simple-audio-card";
- simple-audio-card,name = "Starfive-Pwmdac-Sound-Card";
- simple-audio-card,bitclock-master = <&pwmdac_dailink_master>;
- simple-audio-card,frame-master = <&pwmdac_dailink_master>;
- simple-audio-card,format = "left_j";
- status = "disabled";
+ simple-audio-card,name = "Starfive-Multi-Sound-Card";
+ #address-cells = <1>;
+ #size-cells = <0>;
- pwmdac_dailink_master: simple-audio-card,cpu {
- sound-dai = <&pwmdac>;
- };
+ simple-audio-card,dai-link@0 {
+ reg = <0>;
+ format = "left_j";
+ bitclock-master = <&sndcpu0>;
+ frame-master = <&sndcpu0>;
+ status = "okay";
+
+ sndcpu0: cpu {
+ sound-dai = <&pwmdac>;
+ };
- simple-audio-card,codec {
- sound-dai = <&pwmdac_codec>;
+ codec {
+ sound-dai = <&pwmdac_codec>;
+ };
};
};
* @file pwmdac.h
* @author StarFive Technology
* @version V1.0
- * @date 05/27/2021
+ * @date 05/05/2022
* @brief
******************************************************************************
* @copy
*
- * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
- * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
- * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
- * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
- * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ * PWMDAC driver for the StarFive JH7110 SoC
*
- * <h2><center>© COPYRIGHT 20120 Shanghai StarFive Technology Co., Ltd. </center></h2>
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
*/
#ifndef __STARFIVE_PWMDAC_LOCAL_H
#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
-#define PWMDAC_WDATA 0///PWMDAC_BASE_ADDR
-#define PWMDAC_CTRL 0x04///PWMDAC_BASE_ADDR + 0x04
-#define PWMDAC_SATAE 0x08///PWMDAC_BASE_ADDR + 0x08
-#define PWMDAC_RESERVED 0x0C///PWMDAC_BASE_ADDR + 0x0C
+#define PWMDAC_WDATA 0 /*PWMDAC_BASE_ADDR*/
+#define PWMDAC_CTRL 0x04 /*PWMDAC_BASE_ADDR + 0x04*/
+#define PWMDAC_SATAE 0x08 /*PWMDAC_BASE_ADDR + 0x08*/
+#define PWMDAC_RESERVED 0x0C /*PWMDAC_BASE_ADDR + 0x0C*/
-#define SFC_PWMDAC_SHIFT BIT(1)
-#define SFC_PWMDAC_DUTY_CYCLE BIT(2)
-#define SFC_PWMDAC_CNT_N BIT(4)
+#define SFC_PWMDAC_SHIFT BIT(1)
+#define SFC_PWMDAC_DUTY_CYCLE BIT(2)
+#define SFC_PWMDAC_CNT_N BIT(4)
#define SFC_PWMDAC_LEFT_RIGHT_DATA_CHANGE BIT(13)
-#define SFC_PWMDAC_DATA_MODE BIT(14)
+#define SFC_PWMDAC_DATA_MODE BIT(14)
#define FIFO_UN_FULL 0
#define FIFO_FULL 1
-#define PWMDAC_MCLK (4096000)
+#define PWMDAC_MCLK 4096000
enum pwmdac_lr_change{
NO_CHANGE = 0,
enum pwmdac_shift_bit{
PWMDAC_SHIFT_8 = 8, /*pwmdac shift 8 bit*/
- PWMDAC_SHIFT_10 = 10, /*pwmdac shift 10 bit*/
+ PWMDAC_SHIFT_10 = 10, /*pwmdac shift 10 bit*/
};
enum pwmdac_duty_cycle{
PWMDAC_SAMPLE_CNT_5,
PWMDAC_SAMPLE_CNT_6,
PWMDAC_SAMPLE_CNT_7,
- PWMDAC_SAMPLE_CNT_8 = 1, //(32.468/8) == (12.288/3) == 4.096
+ PWMDAC_SAMPLE_CNT_8 = 1, /*(32.468/8) == (12.288/3) == 4.096*/
PWMDAC_SAMPLE_CNT_9,
PWMDAC_SAMPLE_CNT_10,
PWMDAC_SAMPLE_CNT_11,
bool use_pio;
spinlock_t lock;
int active;
+
+ struct clk *clk_apb0;
+ struct clk *clk_pwmdac_apb;
+ struct clk *clk_pwmdac_core;
+ struct reset_control *rst_apb;
struct device *dev;
struct snd_dmaengine_dai_dma_data play_dma_data;
/**
******************************************************************************
- * @file sf_pwmdac.c
+ * @file starfive_pwmdac.c
* @author StarFive Technology
* @version V1.0
- * @date 05/27/2021
+ * @date 05/05/2022
* @brief
******************************************************************************
* @copy
*
- * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
- * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
- * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
- * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
- * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ * PWMDAC driver for the StarFive JH7110 SoC
*
- * <h2><center>© COPYRIGHT 20120 Shanghai StarFive Technology Co., Ltd. </center></h2>
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
*/
#include <linux/clk.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
-#include "pwmdac.h"
#include <linux/kthread.h>
+#include <linux/reset.h>
+#include "pwmdac.h"
struct ct_pwmdac {
char *name;
static void pwmdac_set(struct sf_pwmdac_dev *dev)
{
- ///8-bit + left + N=16
- pwmdac_set_ctrl_shift(dev, dev->shift_bit);
- pwmdac_set_ctrl_dutyCycle(dev, dev->duty_cycle);
- pwmdac_set_ctrl_N(dev, dev->datan);
- pwmdac_set_ctrl_enable(dev);
+ /*8-bit + left + N=16*/
+ pwmdac_set_ctrl_shift(dev, dev->shift_bit);
+ pwmdac_set_ctrl_dutyCycle(dev, dev->duty_cycle);
+ pwmdac_set_ctrl_N(dev, dev->datan);
+ pwmdac_set_ctrl_enable(dev);
- pwmdac_LR_data_change(dev, dev->lr_change);
- pwmdac_data_mode(dev, dev->data_mode);
+ pwmdac_LR_data_change(dev, dev->lr_change);
+ pwmdac_data_mode(dev, dev->data_mode);
if (dev->shift) {
pwmdac_data_shift(dev, dev->shift);
}
static int sf_pwmdac_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct sf_pwmdac_dev *dev = snd_soc_dai_get_drvdata(dai);
- //pwmdac_set(dev);
return 0;
}
-#if 0
-static int pwmdac_tx_thread(void *dev)
-{
- struct sf_pwmdac_dev *pwmdac_dev = (struct sf_pwmdac_dev *)dev;
-
- set_current_state(TASK_INTERRUPTIBLE);
- while (!schedule_timeout(usecs_to_jiffies(50))) {
- if (pwmdac_dev->tx_thread_exit)
- break;
- if (get_pwmdac_fifo_state(pwmdac_dev)==0) {
- sf_pwmdac_pcm_push_tx(pwmdac_dev);
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- }
-
- pwmdac_dev->tx_thread = NULL;
- return 0;
-}
-#else
int pwmdac_tx_thread(void *dev)
{
return 0;
}
-
-#endif
static int sf_pwmdac_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, NULL);
snd_soc_dai_set_drvdata(dai, dev);
-
+
+ return 0;
+}
+
+static int sf_pwmdac_clks_get(struct platform_device *pdev,
+ struct sf_pwmdac_dev *dev)
+{
+ dev->clk_apb0 = devm_clk_get(&pdev->dev, "apb0");
+ if (IS_ERR(dev->clk_apb0))
+ return PTR_ERR(dev->clk_apb0);
+
+ dev->clk_pwmdac_apb = devm_clk_get(&pdev->dev, "pwmdac-apb");
+ if (IS_ERR(dev->clk_pwmdac_apb))
+ return PTR_ERR(dev->clk_pwmdac_apb);
+
+ dev->clk_pwmdac_core = devm_clk_get(&pdev->dev, "pwmdac-core");
+ if (IS_ERR(dev->clk_pwmdac_core))
+ return PTR_ERR(dev->clk_pwmdac_core);
+
+ return 0;
+}
+
+static int sf_pwmdac_resets_get(struct platform_device *pdev,
+ struct sf_pwmdac_dev *dev)
+{
+ dev->rst_apb = devm_reset_control_get_exclusive(&pdev->dev, "rst-apb");
+ if (IS_ERR(dev->rst_apb)) {
+ dev_err(&pdev->dev, "%s: failed to get pwmdac apb reset control\n", __func__);
+ return PTR_ERR(dev->rst_apb);
+ }
+
return 0;
}
+static int sf_pwmdac_clk_init(struct platform_device *pdev,
+ struct sf_pwmdac_dev *dev)
+{
+ int ret = 0;
+
+ ret = clk_prepare_enable(dev->clk_apb0);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare enable clk_apb0\n");
+ goto err_clk_pwmdac;
+ }
+
+ ret = clk_prepare_enable(dev->clk_pwmdac_apb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare enable clk_pwmdac_apb\n");
+ goto err_clk_pwmdac;
+ }
+
+ ret = clk_prepare_enable(dev->clk_pwmdac_core);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare enable clk_pwmdac_core\n");
+ goto err_clk_pwmdac;
+ }
+ dev_info(&pdev->dev, "clk_apb0 = %lu, clk_pwmdac_apb = %lu, clk_pwmdac_core = %lu\n",
+ clk_get_rate(dev->clk_apb0), clk_get_rate(dev->clk_pwmdac_apb),
+ clk_get_rate(dev->clk_pwmdac_core));
+
+ ret = reset_control_deassert(dev->rst_apb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to deassert apb\n");
+ goto err_clk_pwmdac;
+ }
+
+err_clk_pwmdac:
+ return ret;
+}
+
static int sf_pwmdac_dai_probe(struct snd_soc_dai *dai)
{
struct sf_pwmdac_dev *dev = dev_get_drvdata(dai->dev);
return PTR_ERR(dev->pwmdac_base);
dev->mapbase = res->start;
+
+ ret = sf_pwmdac_clks_get(pdev, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get pwmdac clock\n");
+ return ret;
+ }
+
+ ret = sf_pwmdac_resets_get(pdev, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get pwmdac reset controls\n");
+ return ret;
+ }
+
+ ret = sf_pwmdac_clk_init(pdev, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable pwmdac clock\n");
+ return ret;
+ }
+
dev->dev = &pdev->dev;
dev->mode = shift_8Bit_inverter;
dev->fifo_th = 1;//8byte
pwmdac_config(dev);
dev->use_pio = false;
- //dev->use_pio = true;
dev_set_drvdata(&pdev->dev, dev);
ret = devm_snd_soc_register_component(&pdev->dev, &sf_pwmdac_component,
&pwmdac_dai, 1);
},
};
-module_platform_driver(sf_pwmdac_driver);
-MODULE_AUTHOR("jenny.zhang <jenny.zhang@starfivetech.com>");
+static int __init pwmdac_driver_init(void)
+{
+ return platform_driver_register(&sf_pwmdac_driver);
+}
+
+static void pwmdac_driver_exit(void)
+{
+ platform_driver_unregister(&sf_pwmdac_driver);
+}
+
+late_initcall(pwmdac_driver_init);
+module_exit(pwmdac_driver_exit);
+
+MODULE_AUTHOR("curry.zhang <curry.zhang@starfivetech.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("starfive pwmdac SoC Interface");
MODULE_ALIAS("platform:starfive-pwmdac");