本文共 14937 字,大约阅读时间需要 49 分钟。
cyttsp_ts_wq = create_singlethread_workqueue("cyttsp_ts_wq");
/*
create_workqueue 用于创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程
create_singlethread_workqueue 用于创建workqueue,只创建一个内核线程
destroy_workqueue 释放workqueue队列
schedule_work 调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue——keventd_wq
schedule_delayed_work 延迟一定时间去执行一个具体的任务,功能与schedule_work类似,多了一个延迟时间
*/
if (cyttsp_ts_wq == NULL) { cyttsp_debug("No memory for cyttsp_ts_wq\n"); return -ENOMEM; } ret = i2c_add_driver(&cyttsp_driver); //添加I2C驱动 return ret;}
===================================================
static struct i2c_driver cyttsp_driver = { .driver = { .name = CY_I2C_NAME, .owner = THIS_MODULE, .pm = &cyttsp_pm_ops, //电源管理接口 }, .probe = cyttsp_probe, .remove = __devexit_p(cyttsp_remove), .id_table = cyttsp_id, };
===================================================
static int __devinit cyttsp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cyttsp *ts; int error; int retval = CY_OK; cyttsp_info("Start Probe 1.2\n"); /* allocate and clear memory */ ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL); if (ts == NULL) { cyttsp_xdebug1("err kzalloc for cyttsp\n"); retval = -ENOMEM; }
//前面有觉得奇怪,在cyttsp_driver中
----------------------
static struct i2c_driver cyttsp_driver = { .driver = { .name = CY_I2C_NAME, .owner = THIS_MODULE, .pm = &cyttsp_pm_ops, // 为什么是用这个},
// .suspend = xxx_suspend, //而不是用这两个,这之间有什么区别 // .resume = xxx_resume,
.probe = cyttsp_probe, .remove = __devexit_p(cyttsp_remove), .id_table = cyttsp_id,};
------------------------
// 到这里差不多明白了
.suspend = xxx_suspend, .resume = xxx_resume,
//是系统的睡眠唤醒接口,是不可控的,也就是说:在整个系统睡眠和唤醒时会自动掉用,
//你无法在其他时候进行控制。而
.pm = &cyttsp_pm_ops, // 是在系统睡眠和唤醒的其他时间,你可以用这个接口对设备的睡眠唤醒进行控制。
//具体来讲,因为TP的功耗一般挺大的,如果TP一直处在工作状态,对系统功耗是一个很大的负担,
//一般的做法是在无触碰的情况下让TP睡眠,有触碰时,用中断唤醒TP进入工作状态,所以用了
//这个接口。
// 有兴趣的可以看看这个
/* Enable runtime PM ops, start in ACTIVE mode */
// 启用运行时电源管理操作接口,在主动模式启动
error = pm_runtime_set_active(&client->dev);
if (error < 0)dev_dbg(&client->dev, "unable to set runtime pm state\n");
pm_runtime_enable(&client->dev); if (!(retval < CY_OK)) { /* register driver_data */ ts->client = client; ts->platform_data = client->dev.platform_data; if (ts->platform_data->fw_fname) strncpy(ts->fw_fname, ts->platform_data->fw_fname, FW_FNAME_LEN - 1); else strncpy(ts->fw_fname, "cyttsp.hex", FW_FNAME_LEN - 1); i2c_set_clientdata(client, ts);error = cyttsp_initialize(client, ts);
// 驱动程序初始化,这个函数做一下事情;
// 1 创建并注册一个输入层的输入设备
// 2 使CYTTSP 脱离引导模式
// 3 开启定时器,工作队列
if (error) {
cyttsp_xdebug1("err cyttsp_initialize\n"); if (ts != NULL) { /* deallocate memory */ kfree(ts); } /* i2c_del_driver(&cyttsp_driver); */ retval = -ENODEV; } else cyttsp_openlog(); } #ifdef CONFIG_HAS_EARLYSUSPEND if (!(retval < CY_OK)) { ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ts->early_suspend.suspend = cyttsp_early_suspend; ts->early_suspend.resume = cyttsp_late_resume; register_early_suspend(&ts->early_suspend); } #endif /* CONFIG_HAS_EARLYSUSPEND */device_init_wakeup(&client->dev, ts->platform_data->wakeup);
----------------------------------
static inline int device_init_wakeup(struct device *dev, bool val) { device_set_wakeup_capable(dev, val); //设置设备能不能唤醒 device_set_wakeup_enable(dev, val); //设置设备使不使用唤醒,这都与前面runtime电源管理模式相关 return 0;}
// 设备模型中的所有设备都有两个标志来控制唤醒事件(可使得设备或系统退出低功耗状态)。
// 设两个标志位由总线或者设备驱动用 device_set_wakeup_capable()和
// device_set_wakeup_enable()来初始化。
----------------------------------
mutex_init(&ts->mutex); //初始化互斥锁 cyttsp_info("Start Probe %s\n", \ (retval < CY_OK) ? "FAIL" : "PASS"); return retval;}
===================================================
static int cyttsp_initialize(struct i2c_client *client, struct cyttsp *ts) { struct input_dev *input_device; int error = 0; int retval = CY_OK; u8 id; /* Create the input device and register it. */ input_device = input_allocate_device(); // 为input_device分配内存 if (!input_device) { error = -ENOMEM; cyttsp_xdebug1("err input allocate device\n"); goto error_free_device; } if (!client) { error = ~ENODEV; cyttsp_xdebug1("err client is Null\n"); goto error_free_device; } if (!ts) { error = ~ENODEV; cyttsp_xdebug1("err context is Null\n"); goto error_free_device; } ts->input = input_device; input_device->name = CY_I2C_NAME; input_device->phys = ts->phys; input_device->dev.parent = &client->dev; /* init the touch structures */ //初始化触摸屏结构 ts->num_prv_st_tch = CY_NTCH; for (id = 0; id < CY_NUM_TRK_ID; id++) { ts->act_trk[id] = CY_NTCH; ts->prv_mt_pos[id][CY_XPOS] = 0; ts->prv_mt_pos[id][CY_YPOS] = 0; } for (id = 0; id < CY_NUM_MT_TCH_ID; id++) ts->prv_mt_tch[id] = CY_IGNR_TCH; for (id = 0; id < CY_NUM_ST_TCH_ID; id++) ts->prv_st_tch[id] = CY_IGNR_TCH; set_bit(EV_SYN, input_device->evbit); //设置事件类型,添加TP能够上传的事件类型 set_bit(EV_KEY, input_device->evbit); set_bit(EV_ABS, input_device->evbit); set_bit(BTN_TOUCH, input_device->keybit); set_bit(BTN_2, input_device->keybit); if (ts->platform_data->use_gestures) set_bit(BTN_3, input_device->keybit); input_set_abs_params(input_device, ABS_X, ts->platform_data->disp_minx,
ts->platform_data->disp_maxx, 0, 0);
//设置上传数据标志和参数
input_set_abs_params(input_device, ABS_Y, ts->platform_data->disp_miny, ts->platform_data->disp_maxy, 0, 0); input_set_abs_params(input_device, ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0); input_set_abs_params(input_device, ABS_PRESSURE, 0, CY_MAXZ, 0, 0); input_set_abs_params(input_device, ABS_HAT0X, 0, ts->platform_data->panel_maxx, 0, 0); input_set_abs_params(input_device, ABS_HAT0Y, 0, ts->platform_data->panel_maxy, 0, 0); if (ts->platform_data->use_gestures) { input_set_abs_params(input_device, ABS_HAT1X, 0, CY_MAXZ, 0, 0); input_set_abs_params(input_device, ABS_HAT1Y, 0, CY_MAXZ, 0, 0); } if (ts->platform_data->use_mt) { input_set_abs_params(input_device, ABS_MT_POSITION_X, ts->platform_data->disp_minx, ts->platform_data->disp_maxx, 0, 0); input_set_abs_params(input_device, ABS_MT_POSITION_Y, ts->platform_data->disp_miny, ts->platform_data->disp_maxy, 0, 0); input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0); input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0, 0); if (ts->platform_data->use_trk_id) { input_set_abs_params(input_device, ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0, 0); } } /* set dummy key to make driver work with virtual keys */ //设置input_device 具有虚拟键盘功能 input_set_capability(input_device, EV_KEY, KEY_PROG1); cyttsp_info("%s: Register input device\n", CY_I2C_NAME); error = input_register_device(input_device); //注册input_device if (error) { cyttsp_alert("%s: Failed to register input device\n", \ CY_I2C_NAME); retval = error; goto error_free_device; } /* Prepare our worker structure prior to setting up the timer/ISR */ INIT_WORK(&ts->work, cyttsp_xy_worker); //初始话一个工作队列(gpio_is_valid(ts->platform_data->resout_gpio)) { //检查一个GPIO端口的合法性,也就是说,检查这个端口是
//否被用作其他用途。
/* configure touchscreen reset out gpio */ retval = gpio_request(ts->platform_data->resout_gpio, "cyttsp_resout_gpio"); if (retval) { pr_err("%s: unable to request reset gpio %d\n", __func__, ts->platform_data->resout_gpio); goto error_free_device; } retval = gpio_direction_output( ts->platform_data->resout_gpio, 1); if (retval) { pr_err("%s: unable to set direction for gpio %d\n", __func__, ts->platform_data->resout_gpio); goto error_resout_gpio_dir; } } if (gpio_is_valid(ts->platform_data->sleep_gpio)) { /* configure touchscreen sleep gpio */ retval = gpio_request(ts->platform_data->sleep_gpio, "cy8c_sleep_gpio"); if (retval) { pr_err("%s: unable to request sleep gpio %d\n", __func__, ts->platform_data->sleep_gpio); goto error_sleep_gpio_req; } retval = gpio_direction_output( ts->platform_data->sleep_gpio, 0); if (retval) { pr_err("%s: unable to set direction for gpio %d\n", __func__, ts->platform_data->resout_gpio); goto error_sleep_gpio_dir; } } if (gpio_is_valid(ts->platform_data->irq_gpio)) { /* configure touchscreen irq gpio */ retval = gpio_request(ts->platform_data->irq_gpio, "ts_irq_gpio"); if (retval) { pr_err("%s: unable to request gpio [%d]\n", __func__, ts->platform_data->irq_gpio); goto error_irq_gpio_req; } retval = gpio_direction_input(ts->platform_data->irq_gpio); if (retval) { pr_err("%s: unable to set_direction for gpio [%d]\n", __func__, ts->platform_data->irq_gpio); goto error_irq_gpio_dir; } } if (ts->platform_data->regulator_info) { retval = cyttsp_power_device(ts, true); if (retval) { pr_err("%s: Unable to power device %d\n", __func__, retval); goto error_irq_gpio_dir; } } /* Power on the chip and make sure that I/Os are set as specified * in the platform */ if (ts->platform_data->init) { retval = ts->platform_data->init(client); if (retval) { pr_err("%s: ts init failed\n", __func__); goto error_power_device; } }//cyttsp_power_device和ts->platform_data->init 总结起来就是给TP上电
msleep(100); //等待上电稳定,TP进入稳定工作状态 /* check this device active by reading first byte/register */ retval = i2c_smbus_read_byte_data(ts->client, 0x01); if (retval < 0) { pr_err("%s: i2c sanity check failed\n", __func__); goto error_power_device; } retval = cyttsp_power_on(ts); if (retval < 0) { pr_err("%s: cyttsp_power_on failed\n", __func__); goto error_power_device; } /* Timer or Interrupt setup */ //这里提供了两种模式供选择,中断和轮询,这里我们看中断模式 if (ts->client->irq == 0) { cyttsp_info("Setting up timer\n"); setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts); mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT); } else { cyttsp_info("Setting up interrupt\n"); /* request_irq() will also call enable_irq() */ error = request_irq(client->irq, cyttsp_irq, IRQF_TRIGGER_FALLING, client->dev.driver->name, ts); if (error) { cyttsp_alert("error: could not request irq\n"); retval = error; goto error_power_device; } } irq_cnt = 0; irq_cnt_total = 0; irq_err_cnt = 0; atomic_set(&ts->irq_enabled, 1); //原子赋值,使能IRQ retval = device_create_file(&ts->client->dev, &dev_attr_irq_enable); //创建sys/下的接口文件 if (retval < CY_OK) { cyttsp_alert("File device creation failed: %d\n", retval); retval = -ENODEV; goto error_free_irq; } retval = device_create_file(&client->dev, &dev_attr_cyttsp_fw_ver); if (retval) { cyttsp_alert("sysfs entry for firmware version failed\n"); goto error_rm_dev_file_irq_en; } ts->cyttsp_fwloader_mode = 0; retval = device_create_file(&client->dev, &dev_attr_cyttsp_update_fw); if (retval) { cyttsp_alert("sysfs entry for firmware update failed\n"); goto error_rm_dev_file_fw_ver; } retval = device_create_file(&client->dev, &dev_attr_cyttsp_force_update_fw); if (retval) { cyttsp_alert("sysfs entry for force firmware update failed\n"); goto error_rm_dev_file_update_fw; } if (ts->platform_data->correct_fw_ver) { if (g_bl_data.appid_lo != ts->platform_data->correct_fw_ver) printk(KERN_INFO "Please update touchscreen firmware\n"); } retval = device_create_file(&client->dev, &dev_attr_cyttsp_fw_name); if (retval) { cyttsp_alert("sysfs entry for file name selection failed\n"); goto error_rm_dev_file_fupdate_fw; } cyttsp_info("%s: Successful registration\n", CY_I2C_NAME); goto success; error_rm_dev_file_fupdate_fw: device_remove_file(&client->dev, &dev_attr_cyttsp_force_update_fw); error_rm_dev_file_update_fw: device_remove_file(&client->dev, &dev_attr_cyttsp_update_fw); error_rm_dev_file_fw_ver: device_remove_file(&client->dev, &dev_attr_cyttsp_fw_ver); error_rm_dev_file_irq_en: device_remove_file(&client->dev, &dev_attr_irq_enable); error_free_irq: if (ts->client->irq) free_irq(client->irq, ts); error_power_device: if (ts->platform_data->regulator_info) cyttsp_power_device(ts, false); error_irq_gpio_dir: if (gpio_is_valid(ts->platform_data->irq_gpio)) gpio_free(ts->platform_data->irq_gpio); error_irq_gpio_req: if (gpio_is_valid(ts->platform_data->sleep_gpio)) gpio_direction_output(ts->platform_data->sleep_gpio, 1); error_sleep_gpio_dir: if (gpio_is_valid(ts->platform_data->sleep_gpio)) gpio_free(ts->platform_data->sleep_gpio); error_sleep_gpio_req: if (gpio_is_valid(ts->platform_data->resout_gpio)) gpio_direction_output(ts->platform_data->resout_gpio, 0); error_resout_gpio_dir: if (gpio_is_valid(ts->platform_data->resout_gpio)) gpio_free(ts->platform_data->resout_gpio); error_free_device: if (input_device) input_free_device(input_device); success: return retval;
}
===================================================
static irqreturn_t cyttsp_irq(int irq, void *handle) { struct cyttsp *ts = (struct cyttsp *) handle; cyttsp_xdebug("%s: Got IRQ\n", CY_I2C_NAME); /* disable further interrupts until this interrupt is processed */ disable_irq_nosync(ts->client->irq); /* schedule motion signal handling */queue_work(cyttsp_ts_wq, &ts->work);
--------------------------------------------
//前面已经初始化
INIT_WORK(&ts->work, cyttsp_xy_worker);
--------------------------------------------
return IRQ_HANDLED;
}
===================================================
//这一段还真TMD长 ,一句话,就是上报数据给 驱动中注册的INPUT,上层可以通过他读取数据。
void cyttsp_xy_worker(struct work_struct *work) { 。。。。。。
if (cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) { input_report_abs(ts->input, ABS_X, st_x1); input_report_abs(ts->input, ABS_Y, st_y1); input_report_abs(ts->input, ABS_PRESSURE, st_z1); input_report_key(ts->input, BTN_TOUCH, CY_TCH); input_report_abs(ts->input, ABS_TOOL_WIDTH, curr_tool_width); cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \ cur_st_tch[CY_ST_FNGR1_IDX], \ st_x1, st_y1, st_z1); if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) { input_report_key(ts->input, BTN_2, CY_TCH); input_report_abs(ts->input, ABS_HAT0X, st_x2); input_report_abs(ts->input, ABS_HAT0Y, st_y2); cyttsp_debug("ST->F2:%3d X:%3d Y:%3d Z:%3d\n", \ cur_st_tch[CY_ST_FNGR2_IDX], st_x2, st_y2, st_z2); } else { input_report_key(ts->input, BTN_2, CY_NTCH); } } else { input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH); input_report_key(ts->input, BTN_TOUCH, CY_NTCH); input_report_key(ts->input, BTN_2, CY_NTCH); } /* update platform data for the current single touch info */ ts->prv_st_tch[CY_ST_FNGR1_IDX] = cur_st_tch[CY_ST_FNGR1_IDX]; ts->prv_st_tch[CY_ST_FNGR2_IDX] = cur_st_tch[CY_ST_FNGR2_IDX]; } /* handle Multi-touch signals */ if (ts->platform_data->use_mt) { if (ts->platform_data->use_trk_id) { /* terminate any previous touch where the track * is missing from the current event */ for (id = 0; id < CY_NUM_TRK_ID; id++) { if ((ts->act_trk[id] != CY_NTCH) && (cur_trk[id] == CY_NTCH)) { input_report_abs(ts->input, ABS_MT_TRACKING_ID, id); input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, CY_NTCH); input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, curr_tool_width); input_report_abs(ts->input, ABS_MT_POSITION_X, ts->prv_mt_pos[id][CY_XPOS]); input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->prv_mt_pos[id][CY_YPOS]); CY_MT_SYNC(ts->input); ts->act_trk[id] = CY_NTCH; ts->prv_mt_pos[id][CY_XPOS] = 0; ts->prv_mt_pos[id][CY_YPOS] = 0; } } /* set Multi-Touch current event signals */
。。。。。。
return; }
转载地址:http://qzbsi.baihongyu.com/