am5728定时器输入捕获pwm的linux驱动
时间: 2023-07-19 16:08:07 浏览: 150
linux下的PWM驱动程序
4星 · 用户满意度95%
AM5728是TI公司的一款芯片,其定时器输入捕获PWM的Linux驱动可以通过以下步骤实现:
1. 在设备树中定义定时器和PWM设备节点,包括设备地址、中断号、时钟源等信息。
2. 在内核中编写驱动代码,包括初始化定时器和PWM设备、设置输入捕获模式、中断处理函数等。
3. 在应用层中使用ioctl系统调用配置PWM输出和读取输入捕获值。
具体实现细节可以参考TI公司提供的AM5728参考设计文档和内核源码。
以下是一个简单的驱动程序示例,仅供参考:
```c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/pwm.h>
#include <linux/timer.h>
#include <linux/delay.h>
#define TIMER0_BASE 0x48320000
#define PWM0_BASE 0x48302000
#define TIOCP_CFG 0x010
#define TCLR 0x024
#define TCRR 0x028
#define TISR 0x024
#define IRQSTATUS_RAW_0 0x018
/* PWM registers */
#define PWMSS_CTRL 0x40
#define PWMSS_CH0_CTRL 0x100
#define PWMSS_CH0_PERIOD 0x104
#define PWMSS_CH0_DUTY 0x108
static struct timer_list my_timer;
static struct pwm_device *pwm_dev;
static void *timer0_base, *pwm0_base;
static int irq_num;
static int pwm_period = 1000000; // 1ms
static int pwm_duty = 0;
static void my_timer_callback(unsigned long data)
{
int val;
void *base = timer0_base;
if(ioread32(base + TISR) & (1 << 4)) // check if capture event occurred
{
val = ioread32(base + TCRR); // read the timer counter value
printk(KERN_INFO "Timer Counter Value: %d\n", val);
}
mod_timer(&my_timer, jiffies + msecs_to_jiffies(100)); // reschedule the timer
}
static irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{
void *base = timer0_base;
iowrite32(0x2, base + IRQSTATUS_RAW_0); // clear the interrupt status
return IRQ_HANDLED;
}
static int am5728_pwm_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
void *base;
/* Get the base address of the timer0 device */
timer0_base = of_iomap(np, 0);
if(!timer0_base)
{
printk(KERN_ERR "Failed to map timer0 device\n");
return -ENODEV;
}
/* Get the base address of the PWM0 device */
pwm0_base = ioremap(PWM0_BASE, 0x1000);
if(!pwm0_base)
{
printk(KERN_ERR "Failed to map PWM0 device\n");
return -ENODEV;
}
/* Configure the timer0 device */
base = timer0_base;
iowrite32(0x2, base + TIOCP_CFG); // put the timer in reset mode
iowrite32(0, base + TCLR); // disable the timer
iowrite32(0xFFFFFFFF, base + TCRR); // set the initial timer count value
iowrite32(0x00C2, base + TCLR); // enable the timer in auto-reload mode with prescaler 2
/* Configure the PWM0 device */
pwm_dev = pwm_request(0, "pwm0");
if(IS_ERR(pwm_dev))
{
printk(KERN_ERR "Failed to request PWM0 device\n");
return PTR_ERR(pwm_dev);
}
base = pwm0_base;
iowrite32(0x2, base + PWMSS_CTRL); // put the PWM subsystem in reset mode
iowrite32(0, base + PWMSS_CH0_CTRL); // disable the PWM channel
iowrite32(pwm_period, base + PWMSS_CH0_PERIOD); // set the PWM period
iowrite32(pwm_duty, base + PWMSS_CH0_DUTY); // set the PWM duty cycle
iowrite32(0x80, base + PWMSS_CH0_CTRL); // enable the PWM channel with active high polarity
/* Configure the interrupt */
irq_num = irq_of_parse_and_map(np, 0);
if(request_irq(irq_num, my_interrupt_handler, IRQF_TRIGGER_RISING, "am5728_timer0", NULL))
{
printk(KERN_ERR "Failed to request interrupt\n");
return -EBUSY;
}
/* Start the timer */
mod_timer(&my_timer, jiffies + msecs_to_jiffies(100));
printk(KERN_INFO "AM5728 PWM driver initialized\n");
return 0;
}
static int am5728_pwm_remove(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
/* Stop the timer */
del_timer(&my_timer);
/* Free the PWM device */
pwm_free(pwm_dev);
/* Release the interrupt */
free_irq(irq_num, NULL);
/* Unmap the device memory */
iounmap(pwm0_base);
iounmap(timer0_base);
printk(KERN_INFO "AM5728 PWM driver removed\n");
return 0;
}
static struct of_device_id am5728_pwm_of_match[] = {
{ .compatible = "ti,am5728-pwm", },
{},
};
MODULE_DEVICE_TABLE(of, am5728_pwm_of_match);
static struct platform_driver am5728_pwm_driver = {
.probe = am5728_pwm_probe,
.remove = am5728_pwm_remove,
.driver = {
.name = "am5728-pwm",
.of_match_table = am5728_pwm_of_match,
.owner = THIS_MODULE,
},
};
static void my_timer_init(void)
{
init_timer(&my_timer);
my_timer.function = my_timer_callback;
my_timer.expires = jiffies + msecs_to_jiffies(100);
my_timer.data = 0;
}
static int __init am5728_pwm_init(void)
{
my_timer_init();
return platform_driver_register(&am5728_pwm_driver);
}
static void __exit am5728_pwm_exit(void)
{
platform_driver_unregister(&am5728_pwm_driver);
}
module_init(am5728_pwm_init);
module_exit(am5728_pwm_exit);
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("AM5728 PWM driver");
MODULE_LICENSE("GPL");
```
注意:以上代码仅供参考,实际情况可能会有所不同,需要根据具体芯片和板子进行修改。同时,使用时需要将代码编译成内核模块并加载到内核中。
阅读全文