d. 在Vibrator的kernel driver中,通过hrtimer实现震动时间的精确控制
e. 通过控制流经Vibrator的电压差来控制Vibrator的震动幅度;Vibrator连这两路电压VDD和Vout, Vout可以被控制(VIB_DRV_N),所以Vibrator的压差Vm=VDD-Vout
二、基于STE Riogrande 平台的 vibrator驱动实现
1. 驱动代码kernel/drivers/staging/android/ste_timed_vibra.c
2. 注册的驱动位于 /sys/devices/platform/ste_timed_output_vibra.0/
a. @ste_timed_vibra.c, 有
static struct platform_driver ste_timed_vibra_driver = {
.driver = {
.name = "ste_timed_output_vibra",
.owner = THIS_MODULE,
},
.probe = ste_timed_vibra_probe,
.remove = __devexit_p(ste_timed_vibra_remove)
};
b. platform_driver_register(&ste_timed_vibra_driver); 如此注册vibrator为platform驱动/sys/devices/platform/ste_timed_output_vibra.0/
3. 注册vibrator设备@kernel/arch/arm/mach-ux500/board-mop500-vibra.c
static struct platform_device ux500_vibra_device = {
.name = "ste_timed_output_vibra",
};
platform_device_register(&ux500_vibra_device);
4. 如何注册/sys/class/timed_output/vibrator/enable
a. ste_timed_vibra_probe@ste_timed_vibra.c有
vinfo->tdev.name = "vibrator";
vinfo->tdev.enable = vibra_enable;
vinfo->tdev.get_time = vibra_get_time;
ret = timed_output_dev_register(&vinfo->tdev);
b. timed_output_dev_register@kernel/drivers/staging/android/timed_output.c
ret = create_timed_output_class();-->timed_output_class = class_create(THIS_MODULE, "timed_output"); //创建sys/class/timed_output
tdev->dev = device_create(timed_output_class, NULL,MKDEV(0, tdev->index), NULL, tdev->name);//创建"vibrator" device
ret = device_create_file(tdev->dev, &dev_attr_enable);
5. #echo 1000 > /sys/class/timed_output/vibrator/enable; 调用函数的call stack
a. enable_store@timed_output.c; 有tdev->enable(tdev, value);
b. vibra_enable@ste_timed_vibra.c; 有queue_work(vinfo->enable_workqueue, &vinfo->enable_work);vinfo->queued_timeout = timeout(为-1);
c. vibra_enable_work@ste_timed_vibra.c; [vinfo->vibra_state = STE_VIBRA_IDLE]
d. vibra_control(vinfo); [vinfo->vibra_state = STE_VIBRA_BOOST]
vinfo->pdata->timed_vibra_control(100, -100, 100, -100); -->ux500_ab8500_audio_pwm_vibra@kernel/sound/soc/ux500/ux500_ab8500.c
hrtimer_start(&vinfo->vibra_timer, ktime, HRTIMER_MODE_REL); //比如设置的60ms表示vibrator启动时间, 则60ms后会启动hrtimer 的运行函数vibra_timer_expired
e. vibra_timer_expired@ste_timed_vibra.c; [vinfo->vibra_state = STE_VIBRA_BOOST]
queue_work(vinfo->vibra_workqueue, &vinfo->vibra_work);
f. vibra_control_work-->vibra_control; [vinfo->vibra_state = STE_VIBRA_ON]
vinfo->pdata->timed_vibra_control(50, -50, 50, -50);
hrtimer_start(&vinfo->vibra_timer, ktime, HRTIMER_MODE_REL); //此时设置的hrtimer延时为0了,表示马上执行vibra_timer_expired; 如果设置enable的时间10000,就是100000ms-60ms后再启动vibra_timer_expired
g. vibra_timer_expired@ste_timed_vibra.c; [vinfo->vibra_state = STE_VIBRA_ON]
queue_work(vinfo->vibra_workqueue, &vinfo->vibra_work);
h. vibra_control_work-->vibra_control; [vinfo->vibra_state = STE_VIBRA_OFF]
vinfo->pdata->timed_vibra_control(-50, 50, -50, 50);
hrtimer_start(&vinfo->vibra_timer, ktime, HRTIMER_MODE_REL); //比如设置的60ms表示vibrator的关闭时间, 则60ms后会启动hrtimer 的运行函数vibra_timer_expired
i. vibra_timer_expired@ste_timed_vibra.c; [vinfo->vibra_state = STE_VIBRA_OFF]
queue_work(vinfo->vibra_workqueue, &vinfo->vibra_work);
j. vibra_control_work-->vibra_control; [vinfo->vibra_state = STE_VIBRA_IDLE]
vinfo->pdata->timed_vibra_control(0,0,0,0); //表示关闭vibrator
k. 到此一次完整的vibrator 震动过程完成了,另外该震动模式是用的no linear vibrator
开始操作Vibrator ;启动一工作队列workquence[enable work]
Vibrator 启动(60ms),起震 ;启动一定时器hrtimer,开始60ms计时,启动另一工作队列 workquence[contol work]
Vibrator 运行(震动时间 = 总时间-60ms),平稳震动 ;启动一定时器hrtimer,开始计时
Vibrator 停止(60ms),减震 ;定时器到点触发,启动另一工作队列 workquence[contol work]
Vibrator 关闭 ;完全关闭
6. hrtimer 高精度定时器的使用
a. void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,enum hrtimer_mode mode)
hrtimer_init(&vinfo->vibra_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);//初始化
b. vinfo->vibra_timer.function = vibra_timer_expired; 设置timer的执行函数
c. ktime_t hrtimer_get_remaining(const struct hrtimer *timer) //得到启动hrtimer还需要等待的时间
remain = hrtimer_get_remaining(&vinfo->vibra_timer);
d. int hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)//启动hrtimer,开始计时
ktime_t ktime;
ktime = ktime_set((val / MSEC_PER_SEC), (val % MSEC_PER_SEC) * NSEC_PER_MSEC),
hrtimer_start(&vinfo->vibra_timer, ktime, HRTIMER_MODE_REL);
e. static inline int hrtimer_restart(struct hrtimer *timer)//重新设置延时时间
f. int hrtimer_cancel(struct hrtimer *timer)//取消该定时器,如果定时器的函数已经运行,则等到运行完后再取消
7. 通常基于Android的Timed Output驱动框架实现,Vibrator的驱动程序只需要实现振动的接口即可,这是一个输出设备,需要接受振动时间作为参数。
由于比较简单,因此Vibrator的驱动程序可以使用多种方式来实现。在Android中,推荐基于Android内核定义Timed Output驱动程序框架来实现Vibrator的驱动程序。Timed Output的含义为定时输出,用于定时发出某个输出。
实际上,这种驱动程序依然是基于sys文件系统来完成的。drivers/staging/android/目录timed_output.h中定义timed_output_dev结构体,其中包含enable和get_time这两个函数指针,实现结构体后,使用timed_output_dev_register()和timed_output_dev_unregister()函数注册和注销即可。
Timed Output驱动程序框架将为每个设备在/sys/class/timed_output/目录中建立一个子目录,设备子目录中的enable文件就是设备的控制文件。读enable文件表示获得剩余时间,写这个文件表示根据时间振动。Timed Output驱动的设备调试,通过sys文件系统即可。
对于Vibrator设备,其实现的Timed Output驱动程序的名称应该为“vibrator”。因此Vibrator设备在sys文件系统中的方法如下所示:
# echo "10000" > /sys/class/timed_output/vibrator/enable
# cat /sys/class/timed_output/vibrator/enable
3290
# echo "0" > /sys/class/timed_output/vibrator/enable
对于enable文件,“写”表示使能指定的时间,“读”表示获取剩余时间。
8. 该Vibrator的驱动电压差是用通过 PWM来实现的,通过平均电压可看到 输入压差,从而控制Vibrator的震动幅度