PWM(二) A133 Android12 Linux-5.4 S_PWM无波形

A133 Android12 Linux-5.4 S_PWM无波形

device 补丁

configs/b6/linux-5.4/board.dts | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/configs/b6/linux-5.4/board.dts b/configs/b6/linux-5.4/board.dts
--- a/configs/b6/linux-5.4/board.dts
+++ b/configs/b6/linux-5.4/board.dts
@@ -30,6 +30,18 @@
 
 };
 
+&r_pio {
+	s_pwm0_pin_a: s_pwm0_pin_a {
+		allwinner,pins = "PL10";
+		allwinner,function = "s_pwm0";
+	};
+
+	s_pwm0_pin_b: s_pwm0_pin_b {
+		allwinner,pins = "PL10";
+		allwinner,function = "gpio_in";
+	};
+};
+
 &pio{
 	vcc-pe-supply = <&reg_pio2_8>;
 	vcc-pg-supply = <&reg_pio1_8>;
@@ -854,6 +866,7 @@
 	pinctrl-names = "active", "sleep";
 	pinctrl-0 = <&pwm0_pin_a>;
 	pinctrl-1 = <&pwm0_pin_b>;
+	status = "okay";
 };
 
 &pwm1 {
@@ -862,6 +875,13 @@
 	pinctrl-1 = <&pwm1_pin_b>;
 };
 
+&s_pwm0 {
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&s_pwm0_pin_a>;
+	pinctrl-1 = <&s_pwm0_pin_b>;
+	status = "okay";
+};
+
 &spi0 {
 	spi_slave_mode = <0>;
 	status = "disabled";
-- 
2.7.4

kernel

diff --git a/arch/arm64/boot/dts/sunxi/sun50iw10p1.dtsi
--- a/arch/arm64/boot/dts/sunxi/sun50iw10p1.dtsi
+++ b/arch/arm64/boot/dts/sunxi/sun50iw10p1.dtsi
@@ -62,6 +62,9 @@
 		pwm7 = &pwm7;
 		pwm8 = &pwm8;
 		pwm9 = &pwm9;
+		s_pwm = &s_pwm;
+		s_pwm0 = &s_pwm0;
+		s_pwm1 = &s_pwm1;
 		global-timer0  = &soc_timer0;
 	};
 
@@ -1295,6 +1298,7 @@
 			pwm-base = <0x0>;
 			sunxi-pwms = <&pwm0>, <&pwm1>, <&pwm2>, <&pwm3>, <&pwm4>,
 				<&pwm5>, <&pwm6>, <&pwm7>, <&pwm8>, <&pwm9>;
+			status = "okay";
 		};
 
 		pwm0: pwm0@300a010 {
@@ -1367,6 +1371,32 @@
 			reg_base = <0x0300a000>;
 		};
 
+		s_pwm: s_pwm@7020c00 {
+			#pwm-cells = <0x3>;
+			compatible = "allwinner,sunxi-s_pwm";
+			reg = <0x0 0x07020c00 0x0 0x400>;
+			clocks = <&r_ccu CLK_R_APB1_PWM>, <&r_ccu CLK_R_APB1_BUS_PWM>;
+			resets = <&r_ccu RST_R_APB1_BUS_PWM>;
+			pwm-number = <2>;
+			pwm-base = <0x10>;
+			sunxi-pwms = <&s_pwm0>, <&s_pwm1>;
+			status = "okay";
+		};
+
+		s_pwm0: s_pwm0@07020c10 {
+			compatible = "allwinner,sunxi-pwm16";
+			pinctrl-names = "active", "sleep";
+			reg = <0x0 0x07020c00 0x0 0x400>;
+			reg_base = <0x07020c00>;
+		};
+
+		s_pwm1: s_pwm1@07020c11 {
+			compatible = "allwinner,sunxi-pwm17";
+			pinctrl-names = "active", "sleep";
+			reg = <0x0 0x07020c00 0x0 0x400>;
+			reg_base = <0x07020c00>;
+		};
+
 		vind0: vind@2000800 {
 			compatible = "allwinner,sunxi-vin-media", "simple-bus";
 			#address-cells = <2>;
diff --git a/drivers/clk/sunxi-ng/ccu-sun50iw10-r.c b/drivers/clk/sunxi-ng/ccu-sun50iw10-r.c
--- a/drivers/clk/sunxi-ng/ccu-sun50iw10-r.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50iw10-r.c
@@ -88,8 +88,8 @@ static SUNXI_CCU_GATE(r_apb1_twd_clk, "r-apb1-twd", "r-apb1",
 
 static const char * const r_apb1_pwm_clk_parents[] = { "dcxo24M", "osc32k",
 						       "iosc" };
-static SUNXI_CCU_MUX(r_apb1_pwm_clk, "r-apb1-pwm", r_apb1_pwm_clk_parents,
-		     0x130, 24, 2, 0);
+static SUNXI_CCU_MUX_WITH_GATE(r_apb1_pwm_clk, "r-apb1-pwm", r_apb1_pwm_clk_parents,
+		     0x130, 24, 2, BIT(31), 0);
 
 static SUNXI_CCU_GATE(r_apb1_bus_pwm_clk, "r-apb1-bus-pwm", "r-apb1",
 		      0x13c, BIT(0), 0);
diff --git a/drivers/pwm/pwm-sunxi-group.c b/drivers/pwm/pwm-sunxi-group.c
--- a/drivers/pwm/pwm-sunxi-group.c
+++ b/drivers/pwm/pwm-sunxi-group.c
@@ -73,6 +73,7 @@ struct sunxi_pwm_chip {
 	void __iomem *base;
 	struct sunxi_pwm_config *config;
 	struct clk	*pwm_clk;
+	struct clk	*pwm_bus_clk;
 	struct reset_control	*pwm_rst_clk;
 	unsigned int g_channel;
 	unsigned int g_polarity;
@@ -174,9 +175,9 @@ static int sunxi_pwm_set_polarity_single(struct pwm_chip *chip,
 	reg_width = PWM_ACT_STA_WIDTH;
 	temp = sunxi_pwm_readl(chip, reg_offset);
 	if (polarity == PWM_POLARITY_NORMAL) /* set single polarity*/
-		temp = SET_BITS(reg_shift, 1, temp, 0);
-	else
 		temp = SET_BITS(reg_shift, 1, temp, 1);
+	else
+		temp = SET_BITS(reg_shift, 1, temp, 0);
 
 	sunxi_pwm_writel(chip, reg_offset, temp);
 
@@ -1286,7 +1287,7 @@ static int sunxi_pwm_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "failed to get pwm number: %d, force to one!\n", ret);
 		/* force to one pwm if read property fail */
 		pwm->chip.npwm = 1;
-		goto err_iomap;
+		goto err_add;
 	}
 
 	/* read property pwm-base */
@@ -1301,52 +1302,64 @@ static int sunxi_pwm_probe(struct platform_device *pdev)
 	pwm->chip.of_xlate = of_pwm_xlate_with_flags;
 	pwm->chip.of_pwm_n_cells = 3;
 
-	/* add pwm chip to pwm-core */
-	ret = pwmchip_add(&pwm->chip);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
-		goto err_add;
-	}
 	platform_set_drvdata(pdev, pwm);
 
 	pwm->config = devm_kzalloc(&pdev->dev, sizeof(*pwm->config) * pwm->chip.npwm, GFP_KERNEL);
 	if (!pwm->config) {
 		dev_err(&pdev->dev, "failed to allocate memory!\n");
-		goto err_alloc;
+		ret = -EINVAL;
+		goto err_add;
 	}
 
 	for (i = 0; i < pwm->chip.npwm; i++) {
 		sub_np = of_parse_phandle(np, "sunxi-pwms", i);
 		if (IS_ERR_OR_NULL(sub_np)) {
 			pr_err("%s: can't parse \"sunxi-pwms\" property\n", __func__);
-			return -EINVAL;
+			ret -EINVAL;
+			goto err_add;
 		}
 
 		pwm_pdevice = of_find_device_by_node(sub_np);
 		ret =	sunxi_pwm_get_config(pwm_pdevice, &pwm->config[i]);
 		if (ret) {
 			pr_err("Get config failed,exit!\n");
-			goto err_get_config;
+			goto err_add;
 		}
 	}
 
 	pwm->pwm_clk = of_clk_get(pdev->dev.of_node, 0);
 	if (IS_ERR_OR_NULL(pwm->pwm_clk)) {
 		pr_err("%s: can't get pwm clk\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_add;
+	}
+
+	pwm->pwm_bus_clk = of_clk_get(pdev->dev.of_node, 1);
+	if (IS_ERR_OR_NULL(pwm->pwm_bus_clk)) {
+		pr_err("%s: can't get pwm bus_clk \n", __func__);
 	}
+
 	pwm->pwm_rst_clk = devm_reset_control_get(&pdev->dev, NULL);
 	if (IS_ERR_OR_NULL(pwm->pwm_rst_clk)) {
 		pr_err("%s: can't get pwm reset clk\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_add;
 	}
 	reset_control_deassert(pwm->pwm_rst_clk);
 	clk_prepare_enable(pwm->pwm_clk);
-  return 0;
 
-err_get_config:
-err_alloc:
-	pwmchip_remove(&pwm->chip);
+	if (!IS_ERR_OR_NULL(pwm->pwm_bus_clk))
+		clk_prepare_enable(pwm->pwm_bus_clk);
+
+	/* add pwm chip to pwm-core */
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		goto err_add;
+	}
+
+	return 0;
+
 err_add:
 	iounmap(pwm->base);
 err_iomap:
@@ -1357,6 +1370,8 @@ static int sunxi_pwm_remove(struct platform_device *pdev)
 {
 	struct sunxi_pwm_chip *pwm = platform_get_drvdata(pdev);
 	clk_disable(pwm->pwm_clk);
+	if (!IS_ERR_OR_NULL(pwm->pwm_bus_clk))
+		clk_disable(pwm->pwm_bus_clk);
 	reset_control_assert(pwm->pwm_rst_clk);
 	return pwmchip_remove(&pwm->chip);
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
在设备树中,A133PWM的配置通常需要以下几个步骤: 1. 在dts文件中定义PWM节点,如: ``` pwm { compatible = "A133,pwm"; #pwm-cells = <2>; status = "okay"; }; ``` 2. 在dts文件中定义PWM所需的时钟节点,如: ``` pwm_clk: pwm-clock { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; clock-output-names = "pwm_clk"; }; ``` 3. 在dts文件中为PWM节点添加所需属性,如: ``` pwm0: pwm@0 { compatible = "A133,pwm"; reg = <0>; #pwm-cells = <2>; pwms = <&pwm_clk 0 0>; clock-names = "pwm_clk"; status = "okay"; }; ``` 其中,`#pwm-cells`指定了PWM cell的数量,通常为2;`pwms`用于指定PWM输出的时钟源和编号,`&pwm_clk`指向时钟节点的引用,`0 0`分别表示时钟源编号和PWM编号。`clock-names`属性用于指定时钟的名称,这里为"pwm_clk"。 4. 在设备驱动中使用`pwm_request()`函数来请求PWM资源,并使用`pwm_config()`和`pwm_enable()`函数来配置和启用PWM输出。 ``` struct pwm_device *pwm_dev; pwm_dev = pwm_request(0, "pwm0"); if (pwm_dev == NULL) { printk(KERN_ERR "Failed to request PWM\n"); return -ENODEV; } if (pwm_config(pwm_dev, duty_ns, period_ns)) { printk(KERN_ERR "Failed to configure PWM\n"); pwm_free(pwm_dev); return -EINVAL; } pwm_enable(pwm_dev); ``` 其中,`pwm_request()`函数用于请求PWM资源,`pwm_config()`函数用于配置PWM占空比和周期,`pwm_enable()`函数用于启用PWM输出。最后,使用`pwm_free()`函数释放PWM资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值