上节说了,寻找马达驱动提供给上层的接口:
其实关键还是一个work工作队列和一个定时器,二者配合并且二者都在前面挂到了haptic数据结构上。剩下的就是怎么用的问题啦?
提供给用户接口函数是在这里注册的:ret = timed_output_dev_register(&haptic->dev);
下面看下这个函数的怎么提供接口的?
int timed_output_dev_register(struct timed_output_dev *tdev)
{
int ret;
/*创建timed_output_class类*/
ret = create_timed_output_class();
/*记录该类的第几个设备*/
tdev->index = atomic_inc_return(&device_count);
/*为该dev创建设备*/
tdev->dev = device_create(timed_output_class, NULL,MKDEV(0, tdev->index), NULL, tdev->name);
/*创建该dev的属性文件,这个就是提供给用户的接口*/
ret = device_create_file(tdev->dev, &dev_attr_enable);
/*设备tdev的私有数据结构*/
dev_set_drvdata(tdev->dev, tdev);
tdev->state = 0;
return ret;
}
看下这个enable属性是怎么工作的?
static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct timed_output_dev *tdev = dev_get_drvdata(dev);
int remaining = tdev->get_time(tdev);//得到剩余的时间
return sprintf(buf, "%d\n", remaining);
}
static ssize_t enable_store(
struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
/*提取驱动数据*/
struct timed_output_dev *tdev = dev_get_drvdata(dev);
int value;
/*格式化输入的数据*/
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
tdev->enable(tdev, value);//把格式化好的数据传入enable函数
return size;
}
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
enable_show,
enable_store);
下面看下该enable函数:
static void isa1200_chip_enable(struct timed_output_dev *dev, int value)
{
/*取出haptic结构体*/
struct isa1200_chip *haptic = container_of(dev, struct isa1200_chip,dev);
unsigned long flags;
spin_lock_irqsave(&haptic->lock, flags);
hrtimer_cancel(&haptic->timer);
if (value == 0)
haptic->enable = 0;//如果为零,则去使能
else {
/*使能并启动定时器*/
value = (value > haptic->pdata->max_timeout ?haptic->pdata->max_timeout : value);
haptic->enable = 1;
hrtimer_start(&haptic->timer,ktime_set(value / 1000, (value % 1000) * 1000000),
HRTIMER_MODE_REL);
}
spin_unlock_irqrestore(&haptic->lock, flags);
/*调用注册的work*/
schedule_work(&haptic->work);
}
下面看看work都做了些神马?
static void isa1200_chip_work(struct work_struct *work)
{
struct isa1200_chip *haptic;
haptic = container_of(work, struct isa1200_chip, work);
isa1200_vib_set(haptic, haptic->enable);//设置使能或者去使能,使马达停止或者开始震
}
继续看下是怎么设置的?
static void isa1200_vib_set(struct isa1200_chip *haptic, int enable)
{
int rc = 0;
/*根据enable的不同值设置马达的不同寄存器*/
if (enable) {
if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
rc = isa1200_write_reg(haptic->client,ISA1200_HCTRL5,ISA1200_HCTRL5_VIB_STRT);
}
} else {
if (haptic->pdata->mode_ctrl == PWM_GEN_MODE)
{
rc = isa1200_write_reg(haptic->client,ISA1200_HCTRL5,ISA1200_HCTRL5_VIB_STOP);
}
}
}
下面看下定时器处理函数:
static enum hrtimer_restart isa1200_vib_timer_func(struct hrtimer *timer)
{
/*如果定时器到期,则去使能,然后调用work去执行真正的去使能*/
struct isa1200_chip *haptic = container_of(timer, struct isa1200_chip,timer);
haptic->enable = 0;
schedule_work(&haptic->work);
return HRTIMER_NORESTART;
}
好啦,到处I2C各个方面都讲完啦,I2C驱动的分析暂时到此。下一个专题会分析input子系统。