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 = <®_pio2_8>;
vcc-pg-supply = <®_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);
}