From f858e3a8ac8cafc5ae243c1080d2629a08d755fb Mon Sep 17 00:00:00 2001 From: ilikara <3435193369@qq.com> Date: Wed, 19 Feb 2025 15:28:05 +0000 Subject: [PATCH 1/3] feat(pwm): pwm capture(WIP) --- drivers/pwm/pwm-loongson.c | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c index 1c7c926fa..e8ae6bbb3 100644 --- a/drivers/pwm/pwm-loongson.c +++ b/drivers/pwm/pwm-loongson.c @@ -22,12 +22,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include /* Loongson PWM registers */ #define LOONGSON_PWM_REG_DUTY 0x4 /* Low Pulse Buffer Register */ @@ -57,8 +60,11 @@ struct pwm_loongson_suspend_store { struct pwm_loongson_ddata { struct clk *clk; void __iomem *base; + u32 irq; + u32 int_count; u64 clk_rate; struct pwm_loongson_suspend_store lss; + struct wait_queue_head capture_wait_queue; }; static inline struct pwm_loongson_ddata *to_pwm_loongson_ddata(struct pwm_chip *chip) @@ -77,6 +83,56 @@ static inline void pwm_loongson_writel(struct pwm_loongson_ddata *ddata, writel(val, ddata->base + offset); } +static irqreturn_t pwm_loongson_isr(int irq, void *dev) +{ + u32 val; + struct pwm_chip *chip = dev; + struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip); + + val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); + if ((val & LOONGSON_PWM_CTRL_INT) == 0) { + return IRQ_NONE; + } + val |= LOONGSON_PWM_CTRL_INT; + pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); + + ddata->int_count++; + + pr_debug("pwm_loongson_isr count %u\n", ddata->int_count); + + return IRQ_HANDLED; +} + +static int pwm_loongson_capture(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_capture *result, + unsigned long timeout) +{ + u32 val; + struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip); + int ret; + + ddata->int_count = 0; + val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); + val |= LOONGSON_PWM_CTRL_EN | LOONGSON_PWM_CTRL_CAPTE | + LOONGSON_PWM_CTRL_INTE | LOONGSON_PWM_CTRL_OE; + pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); + + ret = wait_event_timeout(ddata->capture_wait_queue, + ddata->int_count > 1, timeout); + if (ret == 0) + return -ETIMEDOUT; + + result->period = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_PERIOD); + result->duty_cycle = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_DUTY); + + val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); + val &= ~(LOONGSON_PWM_CTRL_EN | LOONGSON_PWM_CTRL_CAPTE | + LOONGSON_PWM_CTRL_INTE | LOONGSON_PWM_CTRL_OE); + pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); + + return 0; +} + static int pwm_loongson_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity) { @@ -207,6 +263,7 @@ static int pwm_loongson_get_state(struct pwm_chip *chip, struct pwm_device *pwm, } static const struct pwm_ops pwm_loongson_ops = { + .capture = pwm_loongson_capture, .apply = pwm_loongson_apply, .get_state = pwm_loongson_get_state, }; @@ -219,12 +276,22 @@ static int pwm_loongson_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; u32 of_clk_freq = 0; + u32 irq; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -ENODEV; + } chip = devm_pwmchip_alloc(dev, 1, sizeof(*ddata)); if (IS_ERR(chip)) return PTR_ERR(chip); ddata = to_pwm_loongson_ddata(chip); + // 初始化等待队列 + init_waitqueue_head(&ddata->capture_wait_queue); + ddata->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ddata->base)) return PTR_ERR(ddata->base); @@ -247,6 +314,15 @@ static int pwm_loongson_probe(struct platform_device *pdev) #endif } + ddata->irq = irq; + + ret = devm_request_irq(&pdev->dev, ddata->irq, pwm_loongson_isr, + IRQF_SHARED, + dev_name(&pdev->dev), chip); + + if (ret) + dev_err(&pdev->dev, "failure requesting irq %d\n", ret); + /* Explicitly initialize the CTRL register */ pwm_loongson_writel(ddata, 0, LOONGSON_PWM_REG_CTRL); From f3bdbfb5eb01de57221c13b8ccd36f94223fe332 Mon Sep 17 00:00:00 2001 From: ilikara <3435193369@qq.com> Date: Thu, 20 Feb 2025 02:13:05 +0000 Subject: [PATCH 2/3] refactor: update debug message --- drivers/pwm/pwm-loongson.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c index e8ae6bbb3..f749c235b 100644 --- a/drivers/pwm/pwm-loongson.c +++ b/drivers/pwm/pwm-loongson.c @@ -86,7 +86,7 @@ static inline void pwm_loongson_writel(struct pwm_loongson_ddata *ddata, static irqreturn_t pwm_loongson_isr(int irq, void *dev) { u32 val; - struct pwm_chip *chip = dev; + struct pwm_chip *chip = dev_get_drvdata(dev); struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip); val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); @@ -98,7 +98,7 @@ static irqreturn_t pwm_loongson_isr(int irq, void *dev) ddata->int_count++; - pr_debug("pwm_loongson_isr count %u\n", ddata->int_count); + dev_info(dev, "pwm_loongson_isr count %u\n", ddata->int_count); return IRQ_HANDLED; } @@ -108,9 +108,12 @@ static int pwm_loongson_capture(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long timeout) { u32 val; + struct device *dev = pwmchip_parent(chip); struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip); int ret; + dev_info(dev, "int_count: %u\n", ddata->int_count); + ddata->int_count = 0; val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); val |= LOONGSON_PWM_CTRL_EN | LOONGSON_PWM_CTRL_CAPTE | @@ -119,6 +122,10 @@ static int pwm_loongson_capture(struct pwm_chip *chip, struct pwm_device *pwm, ret = wait_event_timeout(ddata->capture_wait_queue, ddata->int_count > 1, timeout); + + dev_info(dev, "ctrl reg: %#08x\n", pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL)); + dev_info(dev, "period reg: %#08x\n", pwm_loongson_readl(ddata, LOONGSON_PWM_REG_PERIOD)); + dev_info(dev, "duty reg: %#08x\n", pwm_loongson_readl(ddata, LOONGSON_PWM_REG_DUTY)); if (ret == 0) return -ETIMEDOUT; @@ -279,6 +286,7 @@ static int pwm_loongson_probe(struct platform_device *pdev) u32 irq; irq = platform_get_irq(pdev, 0); + dev_info(dev, "irq get:%u\n", irq); if (irq <= 0) { dev_err(&pdev->dev, "no irq resource?\n"); return -ENODEV; @@ -316,12 +324,11 @@ static int pwm_loongson_probe(struct platform_device *pdev) ddata->irq = irq; - ret = devm_request_irq(&pdev->dev, ddata->irq, pwm_loongson_isr, - IRQF_SHARED, - dev_name(&pdev->dev), chip); + ret = devm_request_irq(dev, ddata->irq, pwm_loongson_isr, IRQF_SHARED, + dev_name(dev), dev); if (ret) - dev_err(&pdev->dev, "failure requesting irq %d\n", ret); + dev_err(dev, "failure requesting irq %d\n", ret); /* Explicitly initialize the CTRL register */ pwm_loongson_writel(ddata, 0, LOONGSON_PWM_REG_CTRL); From ed6ce74c49ac0cb0900d9a1ad02ee91a4dbc92a2 Mon Sep 17 00:00:00 2001 From: ilikara <3435193369@qq.com> Date: Thu, 20 Feb 2025 04:52:53 +0000 Subject: [PATCH 3/3] feat(pwm): support pwm capture --- drivers/pwm/pwm-loongson.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-loongson.c b/drivers/pwm/pwm-loongson.c index f749c235b..502157a13 100644 --- a/drivers/pwm/pwm-loongson.c +++ b/drivers/pwm/pwm-loongson.c @@ -31,6 +31,7 @@ #include #include #include +#include /* Loongson PWM registers */ #define LOONGSON_PWM_REG_DUTY 0x4 /* Low Pulse Buffer Register */ @@ -112,29 +113,30 @@ static int pwm_loongson_capture(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip); int ret; - dev_info(dev, "int_count: %u\n", ddata->int_count); + pwm_loongson_writel(ddata, 0, LOONGSON_PWM_REG_PERIOD); - ddata->int_count = 0; val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); val |= LOONGSON_PWM_CTRL_EN | LOONGSON_PWM_CTRL_CAPTE | - LOONGSON_PWM_CTRL_INTE | LOONGSON_PWM_CTRL_OE; + LOONGSON_PWM_CTRL_OE; pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); - - ret = wait_event_timeout(ddata->capture_wait_queue, - ddata->int_count > 1, timeout); - - dev_info(dev, "ctrl reg: %#08x\n", pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL)); - dev_info(dev, "period reg: %#08x\n", pwm_loongson_readl(ddata, LOONGSON_PWM_REG_PERIOD)); - dev_info(dev, "duty reg: %#08x\n", pwm_loongson_readl(ddata, LOONGSON_PWM_REG_DUTY)); - if (ret == 0) + ret = readl_poll_timeout(ddata->base + LOONGSON_PWM_REG_PERIOD, val, + val, 10, timeout * 1000); + if (ret < 0) return -ETIMEDOUT; - result->period = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_PERIOD); - result->duty_cycle = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_DUTY); + dev_dbg(dev, "get first period: %u\n", val); + + usleep_range(val * 4 / 100 + 1, val * 4 / 100 + 2); + + val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_PERIOD); + result->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, ddata->clk_rate); + dev_dbg(dev, "get second period: %u\n", val); + val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_DUTY); + result->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, ddata->clk_rate); val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL); val &= ~(LOONGSON_PWM_CTRL_EN | LOONGSON_PWM_CTRL_CAPTE | - LOONGSON_PWM_CTRL_INTE | LOONGSON_PWM_CTRL_OE); + LOONGSON_PWM_CTRL_OE); pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL); return 0;