基于高通MSM 8x60的I2C驱动终极讲解(13)

上节说了,寻找马达驱动提供给上层的接口:
其实关键还是一个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子系统。

你可能感兴趣的:(基于高通MSM 8x60的I2C驱动终极讲解(13))