前言:
讓大家初步了解對高通MSM8916平臺的輸入子系統的實現,給大家提供Dragon Board 410c平臺開發輸入系統設備的思路。(如:按鍵設備、觸摸屏、軌跡球等)
在高通MSM8916平臺中,具有觸摸屏、軌跡球和簡單按鍵功能,這些功能是由Android系統內中的驅動程序實現的,并且需要用戶空間的內容來協助實現。
一、觸摸屏驅動編寫
高通MSM8916平臺的觸摸屏驅動程序的實現文件是drivers/input/touchscreen/synaptics_i2c_rmi4.c,此文件的核心是函數synaptics_ts_probe(),在該函數中需要進行觸摸屏工作模式的初始化,對作為輸出設備的觸摸屏驅動在Linux平臺下的設備名注冊,同事初始化觸摸時間觸發時引起的中斷操作。此函數的實現代碼如下:
static int synaptics_rmi4_probe(
struct i2c_client *client,const struct i2c_device_id *dev_id)
{
int retval = 0;
unsigned char ii;
unsigned char attr_count;
struct synaptics_rmi4_f1a_handle *f1a;
struct synaptics_rmi4_fn *fhandler;
struct synaptics_rmi4_fn *next_fhandler;
struct synaptics_rmi4_data *rmi4_data;
struct synaptics_rmi4_device_info *rmi;
struct synaptics_rmi4_platform_data *platform_data =
client->dev.platform_data;
struct dentry *temp;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
"%s: SMBus byte data not supported\n",
__func__);
return -EIO;
}
if (client->dev.of_node) {
platform_data = devm_kzalloc(&client->dev,
sizeof(*platform_data),
GFP_KERNEL);
if (!platform_data) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
retval = synaptics_rmi4_parse_dt(&client->dev, platform_data);
if (retval)
return retval;
} else {
platform_data = client->dev.platform_data;
}
if (!platform_data) {
dev_err(&client->dev,
"%s: No platform data found\n",
__func__);
return -EINVAL;
}
rmi4_data = kzalloc(sizeof(*rmi4_data) * 2, GFP_KERNEL);
if (!rmi4_data) {
dev_err(&client->dev,
"%s: Failed to alloc mem for rmi4_data\n",
__func__);
return -ENOMEM;
}
rmi = &(rmi4_data->rmi4_mod_info);
rmi4_data->input_dev = input_allocate_device();//創建設備
if (rmi4_data->input_dev == NULL) {
dev_err(&client->dev,
"%s: Failed to allocate input device\n",
__func__);
retval = -ENOMEM;
goto err_input_device;
rmi4_data->i2c_client = client;
rmi4_data->current_page = MASK_8BIT;
rmi4_data->board = platform_data;
rmi4_data->touch_stopped = false;
rmi4_data->sensor_sleep = false;
rmi4_data->irq_enabled = false;
rmi4_data->fw_updating = false;
rmi4_data->suspended = false;
rmi4_data->i2c_read = synaptics_rmi4_i2c_read;
rmi4_data->i2c_write = synaptics_rmi4_i2c_write;
rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
rmi4_data->reset_device = synaptics_rmi4_reset_device;
rmi4_data->flip_x = rmi4_data->board->x_flip;
rmi4_data->flip_y = rmi4_data->board->y_flip;
if (rmi4_data->board->fw_image_name)
snprintf(rmi4_data->fw_image_name, NAME_BUFFER_SIZE, "%s",
rmi4_data->board->fw_image_name);
rmi4_data->input_dev->name = DRIVER_NAME;
rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
rmi4_data->input_dev->id.bustype = BUS_I2C;
rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
rmi4_data->input_dev->dev.parent = &client->dev;
input_set_drvdata(rmi4_data->input_dev, rmi4_data);
set_bit(EV_SYN, rmi4_data->input_dev->evbit);
set_bit(EV_KEY, rmi4_data->input_dev->evbit);
set_bit(EV_ABS, rmi4_data->input_dev->evbit);
set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit);
set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit);
#ifdef INPUT_PROP_DIRECT
set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
#endif
retval = synaptics_rmi4_regulator_configure(rmi4_data, true);
if (retval < 0) {
dev_err(&client->dev, "Failed to configure regulators\n");
goto err_reg_configure;
}
retval = synaptics_rmi4_power_on(rmi4_data, true);
if (retval < 0) {
dev_err(&client->dev, "Failed to power on\n");
goto err_power_device;
}
retval = synaptics_rmi4_pinctrl_init(rmi4_data);
if (!retval && rmi4_data->ts_pinctrl) {
/*
* Pinctrl handle is optional. If pinctrl handle is found
* let pins to be configured in active state. If not found
* continue further without error
*/
if (pinctrl_select_state(rmi4_data->ts_pinctrl,
rmi4_data->pinctrl_state_active))
dev_err(&rmi4_data->i2c_client->dev,
"Can not select %s pinstate\n",
PINCTRL_STATE_ACTIVE);
}
retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
if (retval < 0) {
dev_err(&client->dev, "Failed to configure gpios\n");
goto err_gpio_config;
}
init_waitqueue_head(&rmi4_data->wait);
mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
INIT_LIST_HEAD(&rmi->support_fn_list);
mutex_init(&rmi->support_fn_list_mutex);
retval = synaptics_rmi4_query_device(rmi4_data);
if (retval < 0) {
dev_err(&client->dev,
"%s: Failed to query device\n",
__func__);
goto err_free_gpios;
}
if (platform_data->detect_device) {
retval = synaptics_rmi4_parse_dt_children(&client->dev,
platform_data, rmi4_data);
if (retval < 0)
dev_err(&client->dev,
"%s: Failed to parse device tree property\n",
__func__);
}
if (rmi4_data->board->disp_maxx)
rmi4_data->disp_maxx = rmi4_data->board->disp_maxx;
else
rmi4_data->disp_maxx = rmi4_data->sensor_max_x;
if (rmi4_data->board->disp_maxy)
rmi4_data->disp_maxy = rmi4_data->board->disp_maxy;
else
rmi4_data->disp_maxy = rmi4_data->sensor_max_y;
if (rmi4_data->board->disp_minx)
rmi4_data->disp_minx = rmi4_data->board->disp_minx;
else
rmi4_data->disp_minx = 0;
if (rmi4_data->board->disp_miny)
rmi4_data->disp_miny = rmi4_data->board->disp_miny;
else
rmi4_data->disp_miny = 0;
input_set_abs_params(rmi4_data->input_dev,
ABS_MT_POSITION_X, rmi4_data->disp_minx,
rmi4_data->disp_maxx, 0, 0);
input_set_abs_params(rmi4_data->input_dev,
ABS_MT_POSITION_Y, rmi4_data->disp_miny,
rmi4_data->disp_maxy, 0, 0);
input_set_abs_params(rmi4_data->input_dev,
ABS_PRESSURE, 0, 255, 0, 0);
#ifdef REPORT_2D_W
input_set_abs_params(rmi4_data->input_dev,
ABS_MT_TOUCH_MAJOR, 0,
rmi4_data->max_touch_width, 0, 0);
input_set_abs_params(rmi4_data->input_dev,
ABS_MT_TOUCH_MINOR, 0,
rmi4_data->max_touch_width, 0, 0);
#endif
#ifdef TYPE_B_PROTOCOL
input_mt_init_slots(rmi4_data->input_dev,
rmi4_data->num_of_fingers, 0);
#endif
i2c_set_clientdata(client, rmi4_data);
f1a = NULL;
mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
f1a = fhandler->data;
}
}
mutex_unlock(&rmi->support_fn_list_mutex);
if (f1a) {
for (ii = 0; ii < f1a->valid_button_count; ii++) {
set_bit(f1a->button_map[ii],
rmi4_data->input_dev->keybit);
input_set_capability(rmi4_data->input_dev,
EV_KEY, f1a->button_map[ii]);
}
}
retval = input_register_device(rmi4_data->input_dev);
if (retval) {
dev_err(&client->dev,
"%s: Failed to register input device\n",
__func__);
goto err_register_input;
}
configure_sleep(rmi4_data);
if (!exp_fn_inited) {
mutex_init(&exp_fn_list_mutex);
INIT_LIST_HEAD(&exp_fn_list);
exp_fn_inited = 1;
}
rmi4_data->det_workqueue =
create_singlethread_workqueue("rmi_det_workqueue");
INIT_DELAYED_WORK(&rmi4_data->det_work,
synaptics_rmi4_detection_work);
queue_delayed_work(rmi4_data->det_workqueue,
&rmi4_data->det_work,
msecs_to_jiffies(EXP_FN_DET_INTERVAL));
rmi4_data->irq = gpio_to_irq(platform_data->irq_gpio);
retval = request_threaded_irq(rmi4_data->irq, NULL,
synaptics_rmi4_irq, platform_data->irq_flags,
DRIVER_NAME, rmi4_data);
rmi4_data->irq_enabled = true;
if (retval < 0) {
dev_err(&client->dev,
"%s: Failed to create irq thread\n",
__func__);
goto err_enable_irq;
}
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
retval = sysfs_create_file(&client->dev.kobj,
&attrs[attr_count].attr);
if (retval < 0) {
dev_err(&client->dev,
"%s: Failed to create sysfs attributes\n",
__func__);
goto err_sysfs;
}
}
synaptics_rmi4_sensor_wake(rmi4_data);
retval = synaptics_rmi4_irq_enable(rmi4_data, true);
if (retval < 0) {
dev_err(&client->dev,
"%s: Failed to enable attention interrupt\n",
__func__);
goto err_sysfs;
}
synaptics_secure_touch_init(rmi4_data);
synaptics_secure_touch_stop(rmi4_data, 1);
retval = synaptics_rmi4_check_configuration(rmi4_data);
if (retval < 0) {
dev_err(&client->dev, "Failed to check configuration\n");
return retval;
}
return retval;
err_sysfs:
for (attr_count--; attr_count >= 0; attr_count--) {
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
}
err_create_debugfs_file:
debugfs_remove_recursive(rmi4_data->dir);
err_create_debugfs_dir:
free_irq(rmi4_data->irq, rmi4_data);
err_enable_irq:
cancel_delayed_work_sync(&rmi4_data->det_work);
flush_workqueue(rmi4_data->det_workqueue);
destroy_workqueue(rmi4_data->det_workqueue);
input_unregister_device(rmi4_data->input_dev);
err_register_input:
mutex_lock(&rmi->support_fn_list_mutex);
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry_safe(fhandler, next_fhandler,
&rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
synaptics_rmi4_f1a_kfree(fhandler);
else {
kfree(fhandler->data);
kfree(fhandler->extra);
}
kfree(fhandler);
}
}
mutex_unlock(&rmi->support_fn_list_mutex);
err_free_gpios:
if (gpio_is_valid(rmi4_data->board->reset_gpio))
gpio_free(rmi4_data->board->reset_gpio);
if (gpio_is_valid(rmi4_data->board->irq_gpio))
gpio_free(rmi4_data->board->irq_gpio);
err_gpio_config:
if (rmi4_data->ts_pinctrl) {
if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
devm_pinctrl_put(rmi4_data->ts_pinctrl);
rmi4_data->ts_pinctrl = NULL;
} else {
retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
rmi4_data->pinctrl_state_release);
if (retval)
pr_err("failed to select release pinctrl state\n");
}
}
synaptics_rmi4_power_on(rmi4_data, false);
err_power_device:
synaptics_rmi4_regulator_configure(rmi4_data, false);
err_reg_configure:
input_free_device(rmi4_data->input_dev);
rmi4_data->input_dev = NULL;
err_input_device:
kfree(rmi4_data);
return retval;
}
在上述代碼中,通過I2c_smb_read_byte_data()函數對其寄存器信息進行讀取即可完成其事件信息的獲取,也可以通過i2c_transfer完成對其寄存器信息的批量讀取。
評論
查看更多