!3 feat(pwm): support pwm capture

Merge pull request !3 from Ilikara/feat/pwm-capture
This commit is contained in:
maoxiaochuan
2025-02-20 13:02:27 +00:00
committed by Gitee
+85
View File
@@ -22,12 +22,16 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/units.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
/* Loongson PWM registers */
#define LOONGSON_PWM_REG_DUTY 0x4 /* Low Pulse Buffer Register */
@@ -57,8 +61,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 +84,64 @@ 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_get_drvdata(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++;
dev_info(dev, "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 device *dev = pwmchip_parent(chip);
struct pwm_loongson_ddata *ddata = to_pwm_loongson_ddata(chip);
int ret;
pwm_loongson_writel(ddata, 0, LOONGSON_PWM_REG_PERIOD);
val = pwm_loongson_readl(ddata, LOONGSON_PWM_REG_CTRL);
val |= LOONGSON_PWM_CTRL_EN | LOONGSON_PWM_CTRL_CAPTE |
LOONGSON_PWM_CTRL_OE;
pwm_loongson_writel(ddata, val, LOONGSON_PWM_REG_CTRL);
ret = readl_poll_timeout(ddata->base + LOONGSON_PWM_REG_PERIOD, val,
val, 10, timeout * 1000);
if (ret < 0)
return -ETIMEDOUT;
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_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 +272,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 +285,23 @@ 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);
dev_info(dev, "irq get:%u\n", irq);
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 +324,14 @@ static int pwm_loongson_probe(struct platform_device *pdev)
#endif
}
ddata->irq = irq;
ret = devm_request_irq(dev, ddata->irq, pwm_loongson_isr, IRQF_SHARED,
dev_name(dev), dev);
if (ret)
dev_err(dev, "failure requesting irq %d\n", ret);
/* Explicitly initialize the CTRL register */
pwm_loongson_writel(ddata, 0, LOONGSON_PWM_REG_CTRL);