Loading Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt +32 −6 Original line number Diff line number Diff line Loading @@ -7,10 +7,6 @@ Required properties: - interrupt-parent : parent of interrupt - interrupts : touch sample interrupt to indicate presense or release of fingers on the panel. - atmel,panel-coords : touch panel minimum x, minimum y, maximum x and maximum y resolution - atmel,display-coords : LCD display minimum x, minimum y, maximum x and maximum y resolution - vdd_ana-supply : Analog power supply needed to power device - atmel,irq-gpio : irq gpio - atmel,reset-gpio : reset gpio Loading Loading @@ -50,6 +46,34 @@ Optional property: - atmel,i2cmode-gpio : specify gpio number for i2cmode, which provides internal pull-ups to i2c bus in case there is no hardware pull-up support - atmel,panel-coords : touch panel minimum x, minimum y, maximum x and maximum y resolution. Used to configure the input device. - atmel,display-coords : LCD display minimum x, minimum y, maximum x and maximum y resolution. Used to configure the input device. - atmel,vkey-codes : virtual key code mappings to be used when touch controller does not support sending keycodes and sends coordinates instead. In this case user space programs need to translate coordinates to keycodes instead. Virtual key region sits between display's lower bound and touchscreen's lower bound. Horizontally these keys are evenly distributed between touch boundaries. These codes map to buttons from left to right according to icons on the touch panel. The value of these codes is taken from include/uapi/linux/input.h. If atmel,vkey-codes are specified, it is mandatory to specify atmel,panel-coords and atmel,display-coords as well because rectangular area of each of the virtual key is derived using these two properties. - atmel,create-vkeys : Define this property to create vkey entries for Atmel touchscreen driver. This is used when there are multiple Atmel touchscreen controllers, and everyone has to support virtual keys. Following are the mandatory properties that must be defined inside the cfg nodes: - atmel,family-id - atmel,panel-coords - atmel,display-coords - atmel,vkey-codes Example: i2c@f9966000 { Loading @@ -71,8 +95,6 @@ Example: interrupts = <48 0x0>; vdd_ana-supply = <&pm8941_l18>; vcc_i2c-supply = <&pm8941_lvs1>; atmel,panel-coords = <0 0 479 799>; atmel,display-coords = <0 0 479 799>; /* pins used by touchscreen */ pinctrl-names = "pmx_ts_active","pmx_ts_suspend", "pmx_ts_release"; pinctrl-0 = <&ts_int_active &ts_reset_active>; Loading @@ -88,11 +110,15 @@ Example: 0 0 0 0 0 0 0 0 >; atmel,irq-gpio = <&msmgpio 48 0>; atmel,reset-gpio = <&msmgpio 26 0>; atmel,create-vkeys; atmel,cfg_1 { atmel,family-id = <0x81>; atmel,variant-id = <0x01>; atmel,version = <0x10>; atmel,build = <0xaa>; atmel,panel-coords = <0 0 479 799>; atmel,display-coords = <0 0 479 799>; atmel,vkey-codes = <139 172 158 217>; atmel,config = [ /* Object 6, Instance = 0 */ 00 00 00 00 00 00 Loading drivers/input/touchscreen/atmel_mxt_ts.c +233 −28 Original line number Diff line number Diff line Loading @@ -330,6 +330,18 @@ enum mxt_device_state { INIT, APPMODE, BOOTLOADER }; #define MXT_DEBUGFS_DIR "ts_debug" #define MXT_DEBUGFS_FILE_OBJ "object" #define MXT_DEBUGFS_FILE_SUSPEND "suspend" #define DISP_PROP "atmel,display-coords" #define PANEL_PROP "atmel,panel-coords" #define MAX_BUF_SIZE 256 #define VKEY_VER_CODE "0x01" #define HEIGHT_SCALE_NUM 8 #define HEIGHT_SCALE_DENOM 10 /* numerator and denomenator for border equations */ #define BORDER_ADJUST_NUM 3 #define BORDER_ADJUST_DENOM 4 struct mxt_info { u8 family_id; Loading Loading @@ -397,6 +409,8 @@ struct mxt_data { u32 keyarray_new; u8 t9_max_reportid; u8 t9_min_reportid; u16 t9_ymax_reso; u16 t9_xmax_reso; u8 t15_max_reportid; u8 t15_min_reportid; u8 t42_max_reportid; Loading @@ -418,6 +432,81 @@ struct mxt_data { }; static struct dentry *debug_base; static struct kobject *vkey_kobj; static char *vkey_buf; static ssize_t vkey_show(struct kobject *obj, struct kobj_attribute *attr, char *buf) { strlcpy(buf, vkey_buf, MAX_BUF_SIZE); return strnlen(buf, MAX_BUF_SIZE); } static struct kobj_attribute vkey_obj_attr = { .attr = { .mode = S_IRUGO, .name = "virtualkeys.atmel_mxt_ts", }, .show = vkey_show, }; static struct attribute *vkey_attr[] = { &vkey_obj_attr.attr, NULL, }; static struct attribute_group vkey_grp = { .attrs = vkey_attr, }; static int mxt_virtual_keys_init(struct device *dev, struct mxt_data *data) { int width, height, center_x, center_y; int x1 = 0, x2 = 0, i, c = 0, rc = 0, border; vkey_buf = devm_kzalloc(dev, MAX_BUF_SIZE, GFP_KERNEL); if (!vkey_buf) { dev_err(dev, "Failed to allocate memory\n"); return -ENOMEM; } border = (data->pdata->panel_maxx - data->pdata->disp_maxx) * 2; width = ((data->pdata->disp_maxx - (border * (data->pdata->nvkeys - 1))) / data->pdata->nvkeys); height = (data->pdata->panel_maxy - data->pdata->disp_maxy); center_y = data->pdata->disp_maxy + (height / 2); height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM; x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM; for (i = 0; i < data->pdata->nvkeys; i++) { x1 = x2 + border; x2 = x2 + border + width; center_x = x1 + (x2 - x1) / 2; c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c, "%s:%d:%d:%d:%d:%d\n", VKEY_VER_CODE, data->pdata->vkey_codes[i], center_x, center_y, width, height); } vkey_buf[c] = '\0'; vkey_kobj = kobject_create_and_add("board_properties", NULL); if (!vkey_kobj) { dev_err(dev, "unable to create kobject\n"); return -ENOMEM; } rc = sysfs_create_group(vkey_kobj, &vkey_grp); if (rc) { dev_err(dev, "failed to create attributes\n"); kobject_put(vkey_kobj); } return rc; } static bool mxt_object_readable(unsigned int type) { Loading Loading @@ -1497,6 +1586,7 @@ static int mxt_save_objects(struct mxt_data *data) struct mxt_object *t15_object; struct mxt_object *t42_object; int error; u8 val[4]; /* Store T7 and T9 locally, used in suspend/resume operations */ t7_object = mxt_get_object(data, MXT_GEN_POWER_T7); Loading Loading @@ -1525,6 +1615,18 @@ static int mxt_save_objects(struct mxt_data *data) (t9_object->num_report_ids * (t9_object->instances + 1)) + 1; error = __mxt_read_reg(client, t9_object->start_address + MXT_TOUCH_XRANGE_LSB, 4, val); if (error) { dev_err(&client->dev, "Failed to get X-Y reso\n"); return -EINVAL; } /* Y resolution */ data->t9_ymax_reso = (val[1]<<8) + val[0]; /* X resolution */ data->t9_xmax_reso = (val[3]<<8) + val[2]; if (data->pdata->key_codes) { t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15); if (!t15_object) Loading Loading @@ -1662,8 +1764,9 @@ static int mxt_initialize(struct mxt_data *data) info->matrix_ysize = val; dev_info(&client->dev, "Matrix X Size: %d Matrix Y Size: %d\n", info->matrix_xsize, info->matrix_ysize); "Matrix X Size: %d Matrix Y Size: %d Panel X Resolution: %d Panel Y Resolution: %d\n", info->matrix_xsize, info->matrix_ysize, data->t9_xmax_reso, data->t9_ymax_reso); return 0; Loading Loading @@ -2966,11 +3069,11 @@ static void mxt_debugfs_init(struct mxt_data *data) #ifdef CONFIG_OF static int mxt_get_dt_coords(struct device *dev, char *name, struct mxt_platform_data *pdata) struct device_node *node, struct mxt_platform_data *pdata) { u32 coords[MXT_COORDS_ARR_SIZE]; struct property *prop; struct device_node *np = dev->of_node; struct device_node *np = (node == NULL) ? (dev->of_node) : (node); int coords_size, rc; prop = of_find_property(np, name, NULL); Loading Loading @@ -3048,12 +3151,12 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata) struct property *prop; u32 temp_val; rc = mxt_get_dt_coords(dev, "atmel,panel-coords", pdata); if (rc) rc = mxt_get_dt_coords(dev, "atmel,panel-coords", NULL, pdata); if (rc && (rc != -EINVAL)) return rc; rc = mxt_get_dt_coords(dev, "atmel,display-coords", pdata); if (rc) rc = mxt_get_dt_coords(dev, "atmel,display-coords", NULL, pdata); if (rc && (rc != -EINVAL)) return rc; /* regulator info */ Loading @@ -3074,6 +3177,8 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata) pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio", 0, &pdata->irq_gpio_flags); pdata->create_vkeys = of_property_read_bool(np, "atmel,create-vkeys"); /* keycodes for keyarray object*/ prop = of_find_property(np, "atmel,key-codes", NULL); if (prop) { Loading Loading @@ -3285,6 +3390,85 @@ err_pinctrl_get: return retval; } static int mxt_check_child_node_and_create_vkeys(struct mxt_data *data, struct mxt_platform_data *pdata, struct device_node *np) { u8 family_id; u16 x_reso, y_reso; u32 temp_val, d[MXT_COORDS_ARR_SIZE], p[MXT_COORDS_ARR_SIZE]; int error, proplen; struct i2c_client *client = data->client; if (!of_property_read_u32_array(np, DISP_PROP, d, ARRAY_SIZE(d)) && !of_property_read_u32_array(np, PANEL_PROP, p, ARRAY_SIZE(p)) && !of_property_read_u32(np, "atmel,family-id", &temp_val) && of_find_property(np, "atmel,vkey-codes", &proplen)) { /* Read family id from dt */ family_id = (u8) temp_val; /* Read X resolution of touch panel from dt */ x_reso = (u16) p[2]; /* Read Y resolution of touch panel from dt */ y_reso = (u16) p[3]; /* * Check if family id, x-resolution and y-resolution read from * the child DT node match with those read from the touch * controller. In case there is a match: * 1. Populate platform data * 2. Create /sys/board_properties/virtual_keys.<devicename> * sysfs * Otherwise return -EINVAL to indicate that current child * node's characteristics don't match that of the touch * controller's. */ if (family_id == data->info.family_id && x_reso == data->t9_xmax_reso && y_reso == data->t9_ymax_reso) { /* Populate platform data's display coordinates */ pdata->disp_minx = d[0]; pdata->disp_miny = d[1]; pdata->disp_maxx = d[2]; pdata->disp_maxy = d[3]; /* Populate platform data's panel coordinates */ pdata->panel_minx = p[0]; pdata->panel_miny = p[1]; pdata->panel_maxx = p[2]; pdata->panel_maxy = p[3]; /* Parse vkey-codes property */ pdata->nvkeys = proplen / sizeof(u32); pdata->vkey_codes = devm_kzalloc(&client->dev, sizeof(int) * pdata->nvkeys, GFP_KERNEL); if (!pdata->vkey_codes) return -ENOMEM; error = of_property_read_u32_array(np, "atmel,vkey-codes", pdata->vkey_codes, pdata->nvkeys); if (error) { dev_err(&client->dev, "Unable to read virtual key codes\n"); return error; } error = mxt_virtual_keys_init(&client->dev, data); if (error) { dev_err(&client->dev, "Unable to create virtual keys\n"); return error; } } else return -EINVAL; } else return -EINVAL; return 0; } static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { Loading @@ -3292,6 +3476,7 @@ static int mxt_probe(struct i2c_client *client, struct mxt_data *data; struct input_dev *input_dev; int error, i; struct device_node *child, *np; if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, Loading Loading @@ -3337,25 +3522,6 @@ static int mxt_probe(struct i2c_client *client, __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); /* For single touch */ input_set_abs_params(input_dev, ABS_X, pdata->disp_minx, pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_Y, pdata->disp_miny, pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); /* For multi touch */ input_mt_init_slots(input_dev, MXT_MAX_FINGER, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->disp_minx, pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->disp_miny, pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); /* set key array supported keys */ if (pdata->key_codes) { for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) { Loading Loading @@ -3421,9 +3587,39 @@ static int mxt_probe(struct i2c_client *client, if (error) goto err_configure_gpio; if (pdata->create_vkeys) { np = client->dev.of_node; for_each_child_of_node(np, child) { if (!mxt_check_child_node_and_create_vkeys(data, pdata, child)) { dev_info(&client->dev, "vkeys created successfully\n"); break; } } if (child == NULL) dev_err(&client->dev, "Failed to create vkeys\n"); } /* For single touch */ input_set_abs_params(input_dev, ABS_X, data->pdata->disp_minx, data->pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_Y, data->pdata->disp_miny, data->pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); /* For multi touch */ input_mt_init_slots(input_dev, MXT_MAX_FINGER, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, data->pdata->disp_minx, data->pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, data->pdata->disp_miny, data->pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); error = irq_of_parse_and_map(client->dev.of_node, 0); if (!error) goto err_configure_gpio; goto err_parse_irq; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, pdata->irqflags | IRQF_ONESHOT, Loading Loading @@ -3478,6 +3674,11 @@ err_free_irq: free_irq(client->irq, data); err_free_object: kfree(data->object_table); err_parse_irq: if (data->pdata->create_vkeys) { sysfs_remove_group(vkey_kobj, &vkey_grp); kobject_put(vkey_kobj); } err_configure_gpio: if (gpio_is_valid(pdata->irq_gpio)) gpio_free(pdata->irq_gpio); Loading Loading @@ -3516,6 +3717,10 @@ static int mxt_remove(struct i2c_client *client) struct mxt_data *data = i2c_get_clientdata(client); sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); if (data->pdata->create_vkeys) { sysfs_remove_group(vkey_kobj, &vkey_grp); kobject_put(vkey_kobj); } free_irq(data->irq, data); input_unregister_device(data->input_dev); #if defined(CONFIG_FB) Loading include/linux/i2c/atmel_mxt_ts.h +4 −0 Original line number Diff line number Diff line Loading @@ -88,7 +88,11 @@ struct mxt_platform_data { bool need_calibration; bool no_force_update; bool no_lpm_support; bool create_vkeys; u8 bl_addr; /* Points to the virtual key array */ unsigned int *vkey_codes; unsigned char nvkeys; u8(*read_chg) (void); int (*init_hw) (bool); Loading Loading
Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt +32 −6 Original line number Diff line number Diff line Loading @@ -7,10 +7,6 @@ Required properties: - interrupt-parent : parent of interrupt - interrupts : touch sample interrupt to indicate presense or release of fingers on the panel. - atmel,panel-coords : touch panel minimum x, minimum y, maximum x and maximum y resolution - atmel,display-coords : LCD display minimum x, minimum y, maximum x and maximum y resolution - vdd_ana-supply : Analog power supply needed to power device - atmel,irq-gpio : irq gpio - atmel,reset-gpio : reset gpio Loading Loading @@ -50,6 +46,34 @@ Optional property: - atmel,i2cmode-gpio : specify gpio number for i2cmode, which provides internal pull-ups to i2c bus in case there is no hardware pull-up support - atmel,panel-coords : touch panel minimum x, minimum y, maximum x and maximum y resolution. Used to configure the input device. - atmel,display-coords : LCD display minimum x, minimum y, maximum x and maximum y resolution. Used to configure the input device. - atmel,vkey-codes : virtual key code mappings to be used when touch controller does not support sending keycodes and sends coordinates instead. In this case user space programs need to translate coordinates to keycodes instead. Virtual key region sits between display's lower bound and touchscreen's lower bound. Horizontally these keys are evenly distributed between touch boundaries. These codes map to buttons from left to right according to icons on the touch panel. The value of these codes is taken from include/uapi/linux/input.h. If atmel,vkey-codes are specified, it is mandatory to specify atmel,panel-coords and atmel,display-coords as well because rectangular area of each of the virtual key is derived using these two properties. - atmel,create-vkeys : Define this property to create vkey entries for Atmel touchscreen driver. This is used when there are multiple Atmel touchscreen controllers, and everyone has to support virtual keys. Following are the mandatory properties that must be defined inside the cfg nodes: - atmel,family-id - atmel,panel-coords - atmel,display-coords - atmel,vkey-codes Example: i2c@f9966000 { Loading @@ -71,8 +95,6 @@ Example: interrupts = <48 0x0>; vdd_ana-supply = <&pm8941_l18>; vcc_i2c-supply = <&pm8941_lvs1>; atmel,panel-coords = <0 0 479 799>; atmel,display-coords = <0 0 479 799>; /* pins used by touchscreen */ pinctrl-names = "pmx_ts_active","pmx_ts_suspend", "pmx_ts_release"; pinctrl-0 = <&ts_int_active &ts_reset_active>; Loading @@ -88,11 +110,15 @@ Example: 0 0 0 0 0 0 0 0 >; atmel,irq-gpio = <&msmgpio 48 0>; atmel,reset-gpio = <&msmgpio 26 0>; atmel,create-vkeys; atmel,cfg_1 { atmel,family-id = <0x81>; atmel,variant-id = <0x01>; atmel,version = <0x10>; atmel,build = <0xaa>; atmel,panel-coords = <0 0 479 799>; atmel,display-coords = <0 0 479 799>; atmel,vkey-codes = <139 172 158 217>; atmel,config = [ /* Object 6, Instance = 0 */ 00 00 00 00 00 00 Loading
drivers/input/touchscreen/atmel_mxt_ts.c +233 −28 Original line number Diff line number Diff line Loading @@ -330,6 +330,18 @@ enum mxt_device_state { INIT, APPMODE, BOOTLOADER }; #define MXT_DEBUGFS_DIR "ts_debug" #define MXT_DEBUGFS_FILE_OBJ "object" #define MXT_DEBUGFS_FILE_SUSPEND "suspend" #define DISP_PROP "atmel,display-coords" #define PANEL_PROP "atmel,panel-coords" #define MAX_BUF_SIZE 256 #define VKEY_VER_CODE "0x01" #define HEIGHT_SCALE_NUM 8 #define HEIGHT_SCALE_DENOM 10 /* numerator and denomenator for border equations */ #define BORDER_ADJUST_NUM 3 #define BORDER_ADJUST_DENOM 4 struct mxt_info { u8 family_id; Loading Loading @@ -397,6 +409,8 @@ struct mxt_data { u32 keyarray_new; u8 t9_max_reportid; u8 t9_min_reportid; u16 t9_ymax_reso; u16 t9_xmax_reso; u8 t15_max_reportid; u8 t15_min_reportid; u8 t42_max_reportid; Loading @@ -418,6 +432,81 @@ struct mxt_data { }; static struct dentry *debug_base; static struct kobject *vkey_kobj; static char *vkey_buf; static ssize_t vkey_show(struct kobject *obj, struct kobj_attribute *attr, char *buf) { strlcpy(buf, vkey_buf, MAX_BUF_SIZE); return strnlen(buf, MAX_BUF_SIZE); } static struct kobj_attribute vkey_obj_attr = { .attr = { .mode = S_IRUGO, .name = "virtualkeys.atmel_mxt_ts", }, .show = vkey_show, }; static struct attribute *vkey_attr[] = { &vkey_obj_attr.attr, NULL, }; static struct attribute_group vkey_grp = { .attrs = vkey_attr, }; static int mxt_virtual_keys_init(struct device *dev, struct mxt_data *data) { int width, height, center_x, center_y; int x1 = 0, x2 = 0, i, c = 0, rc = 0, border; vkey_buf = devm_kzalloc(dev, MAX_BUF_SIZE, GFP_KERNEL); if (!vkey_buf) { dev_err(dev, "Failed to allocate memory\n"); return -ENOMEM; } border = (data->pdata->panel_maxx - data->pdata->disp_maxx) * 2; width = ((data->pdata->disp_maxx - (border * (data->pdata->nvkeys - 1))) / data->pdata->nvkeys); height = (data->pdata->panel_maxy - data->pdata->disp_maxy); center_y = data->pdata->disp_maxy + (height / 2); height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM; x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM; for (i = 0; i < data->pdata->nvkeys; i++) { x1 = x2 + border; x2 = x2 + border + width; center_x = x1 + (x2 - x1) / 2; c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c, "%s:%d:%d:%d:%d:%d\n", VKEY_VER_CODE, data->pdata->vkey_codes[i], center_x, center_y, width, height); } vkey_buf[c] = '\0'; vkey_kobj = kobject_create_and_add("board_properties", NULL); if (!vkey_kobj) { dev_err(dev, "unable to create kobject\n"); return -ENOMEM; } rc = sysfs_create_group(vkey_kobj, &vkey_grp); if (rc) { dev_err(dev, "failed to create attributes\n"); kobject_put(vkey_kobj); } return rc; } static bool mxt_object_readable(unsigned int type) { Loading Loading @@ -1497,6 +1586,7 @@ static int mxt_save_objects(struct mxt_data *data) struct mxt_object *t15_object; struct mxt_object *t42_object; int error; u8 val[4]; /* Store T7 and T9 locally, used in suspend/resume operations */ t7_object = mxt_get_object(data, MXT_GEN_POWER_T7); Loading Loading @@ -1525,6 +1615,18 @@ static int mxt_save_objects(struct mxt_data *data) (t9_object->num_report_ids * (t9_object->instances + 1)) + 1; error = __mxt_read_reg(client, t9_object->start_address + MXT_TOUCH_XRANGE_LSB, 4, val); if (error) { dev_err(&client->dev, "Failed to get X-Y reso\n"); return -EINVAL; } /* Y resolution */ data->t9_ymax_reso = (val[1]<<8) + val[0]; /* X resolution */ data->t9_xmax_reso = (val[3]<<8) + val[2]; if (data->pdata->key_codes) { t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15); if (!t15_object) Loading Loading @@ -1662,8 +1764,9 @@ static int mxt_initialize(struct mxt_data *data) info->matrix_ysize = val; dev_info(&client->dev, "Matrix X Size: %d Matrix Y Size: %d\n", info->matrix_xsize, info->matrix_ysize); "Matrix X Size: %d Matrix Y Size: %d Panel X Resolution: %d Panel Y Resolution: %d\n", info->matrix_xsize, info->matrix_ysize, data->t9_xmax_reso, data->t9_ymax_reso); return 0; Loading Loading @@ -2966,11 +3069,11 @@ static void mxt_debugfs_init(struct mxt_data *data) #ifdef CONFIG_OF static int mxt_get_dt_coords(struct device *dev, char *name, struct mxt_platform_data *pdata) struct device_node *node, struct mxt_platform_data *pdata) { u32 coords[MXT_COORDS_ARR_SIZE]; struct property *prop; struct device_node *np = dev->of_node; struct device_node *np = (node == NULL) ? (dev->of_node) : (node); int coords_size, rc; prop = of_find_property(np, name, NULL); Loading Loading @@ -3048,12 +3151,12 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata) struct property *prop; u32 temp_val; rc = mxt_get_dt_coords(dev, "atmel,panel-coords", pdata); if (rc) rc = mxt_get_dt_coords(dev, "atmel,panel-coords", NULL, pdata); if (rc && (rc != -EINVAL)) return rc; rc = mxt_get_dt_coords(dev, "atmel,display-coords", pdata); if (rc) rc = mxt_get_dt_coords(dev, "atmel,display-coords", NULL, pdata); if (rc && (rc != -EINVAL)) return rc; /* regulator info */ Loading @@ -3074,6 +3177,8 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata) pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio", 0, &pdata->irq_gpio_flags); pdata->create_vkeys = of_property_read_bool(np, "atmel,create-vkeys"); /* keycodes for keyarray object*/ prop = of_find_property(np, "atmel,key-codes", NULL); if (prop) { Loading Loading @@ -3285,6 +3390,85 @@ err_pinctrl_get: return retval; } static int mxt_check_child_node_and_create_vkeys(struct mxt_data *data, struct mxt_platform_data *pdata, struct device_node *np) { u8 family_id; u16 x_reso, y_reso; u32 temp_val, d[MXT_COORDS_ARR_SIZE], p[MXT_COORDS_ARR_SIZE]; int error, proplen; struct i2c_client *client = data->client; if (!of_property_read_u32_array(np, DISP_PROP, d, ARRAY_SIZE(d)) && !of_property_read_u32_array(np, PANEL_PROP, p, ARRAY_SIZE(p)) && !of_property_read_u32(np, "atmel,family-id", &temp_val) && of_find_property(np, "atmel,vkey-codes", &proplen)) { /* Read family id from dt */ family_id = (u8) temp_val; /* Read X resolution of touch panel from dt */ x_reso = (u16) p[2]; /* Read Y resolution of touch panel from dt */ y_reso = (u16) p[3]; /* * Check if family id, x-resolution and y-resolution read from * the child DT node match with those read from the touch * controller. In case there is a match: * 1. Populate platform data * 2. Create /sys/board_properties/virtual_keys.<devicename> * sysfs * Otherwise return -EINVAL to indicate that current child * node's characteristics don't match that of the touch * controller's. */ if (family_id == data->info.family_id && x_reso == data->t9_xmax_reso && y_reso == data->t9_ymax_reso) { /* Populate platform data's display coordinates */ pdata->disp_minx = d[0]; pdata->disp_miny = d[1]; pdata->disp_maxx = d[2]; pdata->disp_maxy = d[3]; /* Populate platform data's panel coordinates */ pdata->panel_minx = p[0]; pdata->panel_miny = p[1]; pdata->panel_maxx = p[2]; pdata->panel_maxy = p[3]; /* Parse vkey-codes property */ pdata->nvkeys = proplen / sizeof(u32); pdata->vkey_codes = devm_kzalloc(&client->dev, sizeof(int) * pdata->nvkeys, GFP_KERNEL); if (!pdata->vkey_codes) return -ENOMEM; error = of_property_read_u32_array(np, "atmel,vkey-codes", pdata->vkey_codes, pdata->nvkeys); if (error) { dev_err(&client->dev, "Unable to read virtual key codes\n"); return error; } error = mxt_virtual_keys_init(&client->dev, data); if (error) { dev_err(&client->dev, "Unable to create virtual keys\n"); return error; } } else return -EINVAL; } else return -EINVAL; return 0; } static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { Loading @@ -3292,6 +3476,7 @@ static int mxt_probe(struct i2c_client *client, struct mxt_data *data; struct input_dev *input_dev; int error, i; struct device_node *child, *np; if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, Loading Loading @@ -3337,25 +3522,6 @@ static int mxt_probe(struct i2c_client *client, __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); /* For single touch */ input_set_abs_params(input_dev, ABS_X, pdata->disp_minx, pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_Y, pdata->disp_miny, pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); /* For multi touch */ input_mt_init_slots(input_dev, MXT_MAX_FINGER, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->disp_minx, pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->disp_miny, pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); /* set key array supported keys */ if (pdata->key_codes) { for (i = 0; i < MXT_KEYARRAY_MAX_KEYS; i++) { Loading Loading @@ -3421,9 +3587,39 @@ static int mxt_probe(struct i2c_client *client, if (error) goto err_configure_gpio; if (pdata->create_vkeys) { np = client->dev.of_node; for_each_child_of_node(np, child) { if (!mxt_check_child_node_and_create_vkeys(data, pdata, child)) { dev_info(&client->dev, "vkeys created successfully\n"); break; } } if (child == NULL) dev_err(&client->dev, "Failed to create vkeys\n"); } /* For single touch */ input_set_abs_params(input_dev, ABS_X, data->pdata->disp_minx, data->pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_Y, data->pdata->disp_miny, data->pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); /* For multi touch */ input_mt_init_slots(input_dev, MXT_MAX_FINGER, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, data->pdata->disp_minx, data->pdata->disp_maxx, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, data->pdata->disp_miny, data->pdata->disp_maxy, 0, 0); input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); error = irq_of_parse_and_map(client->dev.of_node, 0); if (!error) goto err_configure_gpio; goto err_parse_irq; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, pdata->irqflags | IRQF_ONESHOT, Loading Loading @@ -3478,6 +3674,11 @@ err_free_irq: free_irq(client->irq, data); err_free_object: kfree(data->object_table); err_parse_irq: if (data->pdata->create_vkeys) { sysfs_remove_group(vkey_kobj, &vkey_grp); kobject_put(vkey_kobj); } err_configure_gpio: if (gpio_is_valid(pdata->irq_gpio)) gpio_free(pdata->irq_gpio); Loading Loading @@ -3516,6 +3717,10 @@ static int mxt_remove(struct i2c_client *client) struct mxt_data *data = i2c_get_clientdata(client); sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); if (data->pdata->create_vkeys) { sysfs_remove_group(vkey_kobj, &vkey_grp); kobject_put(vkey_kobj); } free_irq(data->irq, data); input_unregister_device(data->input_dev); #if defined(CONFIG_FB) Loading
include/linux/i2c/atmel_mxt_ts.h +4 −0 Original line number Diff line number Diff line Loading @@ -88,7 +88,11 @@ struct mxt_platform_data { bool need_calibration; bool no_force_update; bool no_lpm_support; bool create_vkeys; u8 bl_addr; /* Points to the virtual key array */ unsigned int *vkey_codes; unsigned char nvkeys; u8(*read_chg) (void); int (*init_hw) (bool); Loading