1. 驱动编写
简单分析一下csky pwm的control编写。
static const struct of_device_id csky_pwm_matches[] = {
{ .compatible = "pwm-csky" },
{ }
};
static struct platform_driver pwm_csky_driver = {
.driver = {
.name = "csky-pwm",
.of_match_table = of_match_ptr(csky_pwm_matches),
},
.probe = pwm_csky_probe,
.remove = pwm_csky_remove,
};
module_platform_driver(pwm_csky_driver);
有同名的“pwm-csky”设备树被注册,pwm_csky_probe函数被调用。
static int pwm_csky_probe(struct platform_device *pdev)
{
struct csky_pwm_chip *csky_chip;
struct resource *res;
int ret;
dev_dbg(&pdev->dev, "pwm_csky_probe\n");
csky_chip = devm_kzalloc(&pdev->dev, sizeof(*csky_chip), GFP_KERNEL);
if (!csky_chip)
return -ENOMEM;
ret = pwm_csky_parse_dt(pdev, csky_chip);
if (ret)
return ret;
pwm_csky_hwInit(DEASSERT_RESET);
csky_chip->chip.dev = &pdev->dev;
csky_chip->chip.ops = &pwm_csky_ops;
csky_chip->chip.base = -1;
csky_chip->chip.npwm = csky_chip->pwm_channels;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing IO resource\n");
return -ENODEV;
}
csky_chip->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(csky_chip->base))
return PTR_ERR(csky_chip->base);
dev_dbg(&pdev->dev, "res->start:%08x\n", (u32) res->start);
csky_chip->irq = platform_get_irq(pdev, 0);
if (csky_chip->irq < 0) {
printk("No irq %d in DT\n", csky_chip->irq);
return -ENODEV;
}
ret = devm_request_irq(&pdev->dev, csky_chip->irq,
pwm_csky_irq_handler,
IRQF_SHARED, dev_name(&pdev->dev), csky_chip);
if (ret)
return -ENODEV;
#if 0
csky_chip->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(csky_chip->clk))
return PTR_ERR(csky_chip->clk);
ret = clk_prepare_enable(csky_chip->clk);
if (ret)
return ret;
csky_chip->rate = clk_get_rate(csky_chip->clk);
if (csky_chip->rate == 0) {
ret = -EINVAL;
goto out_disable_clk;
}
#endif
csky_chip->rate = 25000000;
spin_lock_init(&csky_pwm_spinlock);
ret = pwmchip_add(&csky_chip->chip);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register PWM chip\n");
goto out_disable_clk;
}
platform_set_drvdata(pdev, csky_chip);
dev_info(&pdev->dev, "csky pwm initialized\n");
return 0;
out_disable_clk:
clk_disable_unprepare(csky_chip->clk);
return ret;
}
pwm_csky_probe做的比较简单,主要就是设置struct pwm_chip结构体,主要包括ops和改PWM控制器的channel个数,npwm。我们看下ops。
static const struct pwm_ops pwm_csky_ops = {
.request = pwm_csky_request,
.free = pwm_csky_free,
.enable = pwm_csky_enable,
.disable = pwm_csky_disable,
.config = pwm_csky_config,
.set_polarity = pwm_csky_set_polarity,
.owner = THIS_MODULE,
};