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] 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);