diff options
Diffstat (limited to 'drivers/input/touchscreen/rmi4/rmi_f11.c')
| -rw-r--r-- | drivers/input/touchscreen/rmi4/rmi_f11.c | 1513 |
1 files changed, 1513 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/rmi4/rmi_f11.c b/drivers/input/touchscreen/rmi4/rmi_f11.c new file mode 100644 index 00000000000..35bb945143d --- /dev/null +++ b/drivers/input/touchscreen/rmi4/rmi_f11.c | |||
| @@ -0,0 +1,1513 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2011 Synaptics Incorporated | ||
| 3 | * Copyright (c) 2011 Unixphere | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/input.h> | ||
| 23 | #include <linux/rmi.h> | ||
| 24 | |||
| 25 | #define F11_MAX_NUM_OF_SENSORS 8 | ||
| 26 | #define F11_MAX_NUM_OF_FINGERS 10 | ||
| 27 | #define F11_MAX_NUM_OF_TOUCH_SHAPES 16 | ||
| 28 | |||
| 29 | #define F11_REL_POS_MIN -128 | ||
| 30 | #define F11_REL_POS_MAX 127 | ||
| 31 | |||
| 32 | #define F11_FINGER_STATE_MASK 0x03 | ||
| 33 | #define F11_FINGER_STATE_SIZE 0x02 | ||
| 34 | #define F11_FINGER_STATE_MASK_N(i) \ | ||
| 35 | (F11_FINGER_STATE_MASK << (i%4 * F11_FINGER_STATE_SIZE)) | ||
| 36 | |||
| 37 | #define F11_FINGER_STATE_VAL_N(f_state, i) \ | ||
| 38 | (f_state >> (i%4 * F11_FINGER_STATE_SIZE)) | ||
| 39 | |||
| 40 | #define F11_CTRL_SENSOR_MAX_X_POS_OFFSET 6 | ||
| 41 | #define F11_CTRL_SENSOR_MAX_Y_POS_OFFSET 8 | ||
| 42 | |||
| 43 | #define F11_CEIL(x, y) (((x) + ((y)-1)) / (y)) | ||
| 44 | |||
| 45 | /* By default, we'll support two fingers if we can't figure out how many we | ||
| 46 | * really need to handle. | ||
| 47 | */ | ||
| 48 | #define DEFAULT_NR_OF_FINGERS 2 | ||
| 49 | #define DEFAULT_XY_MAX 9999 | ||
| 50 | #define DEFAULT_MAX_ABS_MT_PRESSURE 255 | ||
| 51 | #define DEFAULT_MAX_ABS_MT_TOUCH 15 | ||
| 52 | #define DEFAULT_MAX_ABS_MT_ORIENTATION 1 | ||
| 53 | #define DEFAULT_MIN_ABS_MT_TRACKING_ID 1 | ||
| 54 | #define DEFAULT_MAX_ABS_MT_TRACKING_ID 10 | ||
| 55 | #define MAX_LEN 256 | ||
| 56 | |||
| 57 | static ssize_t rmi_fn_11_flip_show(struct device *dev, | ||
| 58 | struct device_attribute *attr, char *buf); | ||
| 59 | |||
| 60 | static ssize_t rmi_fn_11_flip_store(struct device *dev, | ||
| 61 | struct device_attribute *attr, | ||
| 62 | const char *buf, size_t count); | ||
| 63 | |||
| 64 | static ssize_t rmi_fn_11_clip_show(struct device *dev, | ||
| 65 | struct device_attribute *attr, char *buf); | ||
| 66 | |||
| 67 | static ssize_t rmi_fn_11_clip_store(struct device *dev, | ||
| 68 | struct device_attribute *attr, | ||
| 69 | const char *buf, size_t count); | ||
| 70 | |||
| 71 | static ssize_t rmi_fn_11_offset_show(struct device *dev, | ||
| 72 | struct device_attribute *attr, char *buf); | ||
| 73 | |||
| 74 | static ssize_t rmi_fn_11_offset_store(struct device *dev, | ||
| 75 | struct device_attribute *attr, | ||
| 76 | const char *buf, size_t count); | ||
| 77 | |||
| 78 | static ssize_t rmi_fn_11_swap_show(struct device *dev, | ||
| 79 | struct device_attribute *attr, char *buf); | ||
| 80 | |||
| 81 | static ssize_t rmi_fn_11_swap_store(struct device *dev, | ||
| 82 | struct device_attribute *attr, | ||
| 83 | const char *buf, size_t count); | ||
| 84 | |||
| 85 | static ssize_t rmi_fn_11_relreport_show(struct device *dev, | ||
| 86 | struct device_attribute *attr, | ||
| 87 | char *buf); | ||
| 88 | |||
| 89 | static ssize_t rmi_fn_11_relreport_store(struct device *dev, | ||
| 90 | struct device_attribute *attr, | ||
| 91 | const char *buf, size_t count); | ||
| 92 | |||
| 93 | static ssize_t rmi_fn_11_maxPos_show(struct device *dev, | ||
| 94 | struct device_attribute *attr, char *buf); | ||
| 95 | |||
| 96 | static ssize_t rmi_f11_rezero_store(struct device *dev, | ||
| 97 | struct device_attribute *attr, | ||
| 98 | const char *buf, size_t count); | ||
| 99 | |||
| 100 | |||
| 101 | static struct device_attribute attrs[] = { | ||
| 102 | __ATTR(flip, RMI_RW_ATTR, rmi_fn_11_flip_show, rmi_fn_11_flip_store), | ||
| 103 | __ATTR(clip, RMI_RW_ATTR, rmi_fn_11_clip_show, rmi_fn_11_clip_store), | ||
| 104 | __ATTR(offset, RMI_RW_ATTR, | ||
| 105 | rmi_fn_11_offset_show, rmi_fn_11_offset_store), | ||
| 106 | __ATTR(swap, RMI_RW_ATTR, rmi_fn_11_swap_show, rmi_fn_11_swap_store), | ||
| 107 | __ATTR(relreport, RMI_RW_ATTR, | ||
| 108 | rmi_fn_11_relreport_show, rmi_fn_11_relreport_store), | ||
| 109 | __ATTR(maxPos, RMI_RO_ATTR, rmi_fn_11_maxPos_show, rmi_store_error), | ||
| 110 | __ATTR(rezero, RMI_WO_ATTR, rmi_show_error, rmi_f11_rezero_store) | ||
| 111 | }; | ||
| 112 | |||
| 113 | |||
| 114 | union f11_2d_commands { | ||
| 115 | struct { | ||
| 116 | u8 rezero:1; | ||
| 117 | }; | ||
| 118 | u8 reg; | ||
| 119 | }; | ||
| 120 | |||
| 121 | |||
| 122 | struct f11_2d_device_query { | ||
| 123 | union { | ||
| 124 | struct { | ||
| 125 | u8 nbr_of_sensors:3; | ||
| 126 | u8 has_query9:1; | ||
| 127 | u8 has_query11:1; | ||
| 128 | }; | ||
| 129 | u8 f11_2d_query0; | ||
| 130 | }; | ||
| 131 | |||
| 132 | u8 f11_2d_query9; | ||
| 133 | |||
| 134 | union { | ||
| 135 | struct { | ||
| 136 | u8 has_z_tuning:1; | ||
| 137 | u8 has_pos_interpolation_tuning:1; | ||
| 138 | u8 has_w_tuning:1; | ||
| 139 | u8 has_pitch_info:1; | ||
| 140 | u8 has_default_finger_width:1; | ||
| 141 | u8 has_segmentation_aggressiveness:1; | ||
| 142 | u8 has_tx_rw_clip:1; | ||
| 143 | u8 has_drumming_correction:1; | ||
| 144 | }; | ||
| 145 | u8 f11_2d_query11; | ||
| 146 | }; | ||
| 147 | }; | ||
| 148 | |||
| 149 | struct f11_2d_sensor_query { | ||
| 150 | union { | ||
| 151 | struct { | ||
| 152 | /* query1 */ | ||
| 153 | u8 number_of_fingers:3; | ||
| 154 | u8 has_rel:1; | ||
| 155 | u8 has_abs:1; | ||
| 156 | u8 has_gestures:1; | ||
| 157 | u8 has_sensitivity_adjust:1; | ||
| 158 | u8 configurable:1; | ||
| 159 | /* query2 */ | ||
| 160 | u8 num_of_x_electrodes:7; | ||
| 161 | /* query3 */ | ||
| 162 | u8 num_of_y_electrodes:7; | ||
| 163 | /* query4 */ | ||
| 164 | u8 max_electrodes:7; | ||
| 165 | }; | ||
| 166 | u8 f11_2d_query1__4[4]; | ||
| 167 | }; | ||
| 168 | |||
| 169 | union { | ||
| 170 | struct { | ||
| 171 | u8 abs_data_size:3; | ||
| 172 | u8 has_anchored_finger:1; | ||
| 173 | u8 has_adj_hyst:1; | ||
| 174 | u8 has_dribble:1; | ||
| 175 | }; | ||
| 176 | u8 f11_2d_query5; | ||
| 177 | }; | ||
| 178 | |||
| 179 | u8 f11_2d_query6; | ||
| 180 | |||
| 181 | union { | ||
| 182 | struct { | ||
| 183 | u8 has_single_tap:1; | ||
| 184 | u8 has_tap_n_hold:1; | ||
| 185 | u8 has_double_tap:1; | ||
| 186 | u8 has_early_tap:1; | ||
| 187 | u8 has_flick:1; | ||
| 188 | u8 has_press:1; | ||
| 189 | u8 has_pinch:1; | ||
| 190 | u8 padding:1; | ||
| 191 | |||
| 192 | u8 has_palm_det:1; | ||
| 193 | u8 has_rotate:1; | ||
| 194 | u8 has_touch_shapes:1; | ||
| 195 | u8 has_scroll_zones:1; | ||
| 196 | u8 has_individual_scroll_zones:1; | ||
| 197 | u8 has_multi_finger_scroll:1; | ||
| 198 | }; | ||
| 199 | u8 f11_2d_query7__8[2]; | ||
| 200 | }; | ||
| 201 | |||
| 202 | /* Empty */ | ||
| 203 | u8 f11_2d_query9; | ||
| 204 | |||
| 205 | union { | ||
| 206 | struct { | ||
| 207 | u8 nbr_touch_shapes:5; | ||
| 208 | }; | ||
| 209 | u8 f11_2d_query10; | ||
| 210 | }; | ||
| 211 | }; | ||
| 212 | |||
| 213 | struct f11_2d_data_0 { | ||
| 214 | u8 finger_n; | ||
| 215 | }; | ||
| 216 | |||
| 217 | struct f11_2d_data_1_5 { | ||
| 218 | u8 x_msb; | ||
| 219 | u8 y_msb; | ||
| 220 | u8 x_lsb:4; | ||
| 221 | u8 y_lsb:4; | ||
| 222 | u8 w_y:4; | ||
| 223 | u8 w_x:4; | ||
| 224 | u8 z; | ||
| 225 | }; | ||
| 226 | |||
| 227 | struct f11_2d_data_6_7 { | ||
| 228 | s8 delta_x; | ||
| 229 | s8 delta_y; | ||
| 230 | }; | ||
| 231 | |||
| 232 | struct f11_2d_data_8 { | ||
| 233 | u8 single_tap:1; | ||
| 234 | u8 tap_and_hold:1; | ||
| 235 | u8 double_tap:1; | ||
| 236 | u8 early_tap:1; | ||
| 237 | u8 flick:1; | ||
| 238 | u8 press:1; | ||
| 239 | u8 pinch:1; | ||
| 240 | }; | ||
| 241 | |||
| 242 | struct f11_2d_data_9 { | ||
| 243 | u8 palm_detect:1; | ||
| 244 | u8 rotate:1; | ||
| 245 | u8 shape:1; | ||
| 246 | u8 scrollzone:1; | ||
| 247 | u8 finger_count:3; | ||
| 248 | }; | ||
| 249 | |||
| 250 | struct f11_2d_data_10 { | ||
| 251 | u8 pinch_motion; | ||
| 252 | }; | ||
| 253 | |||
| 254 | struct f11_2d_data_10_12 { | ||
| 255 | u8 x_flick_dist; | ||
| 256 | u8 y_flick_dist; | ||
| 257 | u8 flick_time; | ||
| 258 | }; | ||
| 259 | |||
| 260 | struct f11_2d_data_11_12 { | ||
| 261 | u8 motion; | ||
| 262 | u8 finger_separation; | ||
| 263 | }; | ||
| 264 | |||
| 265 | struct f11_2d_data_13 { | ||
| 266 | u8 shape_n; | ||
| 267 | }; | ||
| 268 | |||
| 269 | struct f11_2d_data_14_15 { | ||
| 270 | u8 horizontal; | ||
| 271 | u8 vertical; | ||
| 272 | }; | ||
| 273 | |||
| 274 | struct f11_2d_data_14_17 { | ||
| 275 | u8 x_low; | ||
| 276 | u8 y_right; | ||
| 277 | u8 x_upper; | ||
| 278 | u8 y_left; | ||
| 279 | }; | ||
| 280 | |||
| 281 | struct f11_2d_data { | ||
| 282 | const struct f11_2d_data_0 *f_state; | ||
| 283 | const struct f11_2d_data_1_5 *abs_pos; | ||
| 284 | const struct f11_2d_data_6_7 *rel_pos; | ||
| 285 | const struct f11_2d_data_8 *gest_1; | ||
| 286 | const struct f11_2d_data_9 *gest_2; | ||
| 287 | const struct f11_2d_data_10 *pinch; | ||
| 288 | const struct f11_2d_data_10_12 *flick; | ||
| 289 | const struct f11_2d_data_11_12 *rotate; | ||
| 290 | const struct f11_2d_data_13 *shapes; | ||
| 291 | const struct f11_2d_data_14_15 *multi_scroll; | ||
| 292 | const struct f11_2d_data_14_17 *scroll_zones; | ||
| 293 | }; | ||
| 294 | |||
| 295 | struct f11_2d_sensor { | ||
| 296 | struct rmi_f11_2d_axis_alignment axis_align; | ||
| 297 | struct f11_2d_sensor_query sens_query; | ||
| 298 | struct f11_2d_data data; | ||
| 299 | u16 max_x; | ||
| 300 | u16 max_y; | ||
| 301 | u8 nbr_fingers; | ||
| 302 | u8 finger_tracker[F11_MAX_NUM_OF_FINGERS]; | ||
| 303 | u8 *data_pkt; | ||
| 304 | int pkt_size; | ||
| 305 | u8 sensor_index; | ||
| 306 | char input_name[MAX_LEN]; | ||
| 307 | char input_phys[MAX_LEN]; | ||
| 308 | |||
| 309 | struct input_dev *input; | ||
| 310 | struct input_dev *mouse_input; | ||
| 311 | }; | ||
| 312 | |||
| 313 | struct f11_data { | ||
| 314 | struct f11_2d_device_query dev_query; | ||
| 315 | struct rmi_f11_2d_ctrl dev_controls; | ||
| 316 | struct f11_2d_sensor sensors[F11_MAX_NUM_OF_SENSORS]; | ||
| 317 | }; | ||
| 318 | |||
| 319 | enum finger_state_values { | ||
| 320 | F11_NO_FINGER = 0x00, | ||
| 321 | F11_PRESENT = 0x01, | ||
| 322 | F11_INACCURATE = 0x02, | ||
| 323 | F11_RESERVED = 0x03 | ||
| 324 | }; | ||
| 325 | |||
| 326 | static void rmi_f11_rel_pos_report(struct f11_2d_sensor *sensor, u8 n_finger) | ||
| 327 | { | ||
| 328 | struct f11_2d_data *data = &sensor->data; | ||
| 329 | struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align; | ||
| 330 | s8 x, y; | ||
| 331 | s8 temp; | ||
| 332 | |||
| 333 | x = data->rel_pos[n_finger].delta_x; | ||
| 334 | y = data->rel_pos[n_finger].delta_y; | ||
| 335 | |||
| 336 | x = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)x)); | ||
| 337 | y = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)y)); | ||
| 338 | |||
| 339 | if (axis_align->swap_axes) { | ||
| 340 | temp = x; | ||
| 341 | x = y; | ||
| 342 | y = temp; | ||
| 343 | } | ||
| 344 | if (axis_align->flip_x) | ||
| 345 | x = min(F11_REL_POS_MAX, -x); | ||
| 346 | if (axis_align->flip_y) | ||
| 347 | y = min(F11_REL_POS_MAX, -y); | ||
| 348 | |||
| 349 | if (x || y) { | ||
| 350 | input_report_rel(sensor->input, REL_X, x); | ||
| 351 | input_report_rel(sensor->input, REL_Y, y); | ||
| 352 | input_report_rel(sensor->mouse_input, REL_X, x); | ||
| 353 | input_report_rel(sensor->mouse_input, REL_Y, y); | ||
| 354 | } | ||
| 355 | input_sync(sensor->mouse_input); | ||
| 356 | } | ||
| 357 | |||
| 358 | static void rmi_f11_abs_pos_report(struct f11_2d_sensor *sensor, | ||
| 359 | u8 finger_state, u8 n_finger) | ||
| 360 | { | ||
| 361 | struct f11_2d_data *data = &sensor->data; | ||
| 362 | struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align; | ||
| 363 | int prev_state = sensor->finger_tracker[n_finger]; | ||
| 364 | int x, y, z; | ||
| 365 | int w_x, w_y, w_max, w_min, orient; | ||
| 366 | int temp; | ||
| 367 | if (prev_state && !finger_state) { | ||
| 368 | /* this is a release */ | ||
| 369 | x = y = z = w_max = w_min = orient = 0; | ||
| 370 | } else if (!prev_state && !finger_state) { | ||
| 371 | /* nothing to report */ | ||
| 372 | return; | ||
| 373 | } else { | ||
| 374 | x = ((data->abs_pos[n_finger].x_msb << 4) | | ||
| 375 | data->abs_pos[n_finger].x_lsb); | ||
| 376 | y = ((data->abs_pos[n_finger].y_msb << 4) | | ||
| 377 | data->abs_pos[n_finger].y_lsb); | ||
| 378 | z = data->abs_pos[n_finger].z; | ||
| 379 | w_x = data->abs_pos[n_finger].w_x; | ||
| 380 | w_y = data->abs_pos[n_finger].w_y; | ||
| 381 | w_max = max(w_x, w_y); | ||
| 382 | w_min = min(w_x, w_y); | ||
| 383 | |||
| 384 | if (axis_align->swap_axes) { | ||
| 385 | temp = x; | ||
| 386 | x = y; | ||
| 387 | y = temp; | ||
| 388 | temp = w_x; | ||
| 389 | w_x = w_y; | ||
| 390 | w_y = temp; | ||
| 391 | } | ||
| 392 | |||
| 393 | orient = w_x > w_y ? 1 : 0; | ||
| 394 | |||
| 395 | if (axis_align->flip_x) | ||
| 396 | x = max(sensor->max_x - x, 0); | ||
| 397 | |||
| 398 | if (axis_align->flip_y) | ||
| 399 | y = max(sensor->max_y - y, 0); | ||
| 400 | |||
| 401 | /* | ||
| 402 | ** here checking if X offset or y offset are specified is | ||
| 403 | ** redundant. We just add the offsets or, clip the values | ||
| 404 | ** | ||
| 405 | ** note: offsets need to be done before clipping occurs, | ||
| 406 | ** or we could get funny values that are outside | ||
| 407 | ** clipping boundaries. | ||
| 408 | */ | ||
| 409 | x += axis_align->offset_X; | ||
| 410 | y += axis_align->offset_Y; | ||
| 411 | x = max(axis_align->clip_X_low, x); | ||
| 412 | y = max(axis_align->clip_Y_low, y); | ||
| 413 | if (axis_align->clip_X_high) | ||
| 414 | x = min(axis_align->clip_X_high, x); | ||
| 415 | if (axis_align->clip_Y_high) | ||
| 416 | y = min(axis_align->clip_Y_high, y); | ||
| 417 | |||
| 418 | } | ||
| 419 | |||
| 420 | pr_debug("%s: f_state[%d]:%d - x:%d y:%d z:%d w_max:%d w_min:%d\n", | ||
| 421 | __func__, n_finger, finger_state, x, y, z, w_max, w_min); | ||
| 422 | |||
| 423 | |||
| 424 | #ifdef ABS_MT_PRESSURE | ||
| 425 | input_report_abs(sensor->input, ABS_MT_PRESSURE, z); | ||
| 426 | #endif | ||
| 427 | input_report_abs(sensor->input, ABS_MT_TOUCH_MAJOR, w_max); | ||
| 428 | input_report_abs(sensor->input, ABS_MT_TOUCH_MINOR, w_min); | ||
| 429 | input_report_abs(sensor->input, ABS_MT_ORIENTATION, orient); | ||
| 430 | input_report_abs(sensor->input, ABS_MT_POSITION_X, x); | ||
| 431 | input_report_abs(sensor->input, ABS_MT_POSITION_Y, y); | ||
| 432 | input_report_abs(sensor->input, ABS_MT_TRACKING_ID, n_finger); | ||
| 433 | |||
| 434 | /* MT sync between fingers */ | ||
| 435 | input_mt_sync(sensor->input); | ||
| 436 | sensor->finger_tracker[n_finger] = finger_state; | ||
| 437 | } | ||
| 438 | |||
| 439 | static void rmi_f11_finger_handler(struct f11_2d_sensor *sensor) | ||
| 440 | { | ||
| 441 | const struct f11_2d_data_0 *f_state = sensor->data.f_state; | ||
| 442 | u8 finger_state; | ||
| 443 | u8 finger_pressed_count; | ||
| 444 | u8 i; | ||
| 445 | |||
| 446 | for (i = 0, finger_pressed_count = 0; i < sensor->nbr_fingers; i++) { | ||
| 447 | /* Possible of having 4 fingers per f_statet register */ | ||
| 448 | finger_state = (f_state[i >> 2].finger_n & | ||
| 449 | F11_FINGER_STATE_MASK_N(i)); | ||
| 450 | finger_state = F11_FINGER_STATE_VAL_N(finger_state, i); | ||
| 451 | |||
| 452 | if (finger_state == F11_RESERVED) { | ||
| 453 | pr_err("%s: Invalid finger state[%d]:0x%02x.", __func__, | ||
| 454 | i, finger_state); | ||
| 455 | continue; | ||
| 456 | } else if ((finger_state == F11_PRESENT) || | ||
| 457 | (finger_state == F11_INACCURATE)) { | ||
| 458 | finger_pressed_count++; | ||
| 459 | } | ||
| 460 | |||
| 461 | if (sensor->data.abs_pos) | ||
| 462 | rmi_f11_abs_pos_report(sensor, finger_state, i); | ||
| 463 | |||
| 464 | if (sensor->data.rel_pos) | ||
| 465 | rmi_f11_rel_pos_report(sensor, i); | ||
| 466 | } | ||
| 467 | input_report_key(sensor->input, BTN_TOUCH, finger_pressed_count); | ||
| 468 | input_sync(sensor->input); | ||
| 469 | } | ||
| 470 | |||
| 471 | static inline int rmi_f11_2d_construct_data(struct f11_2d_sensor *sensor) | ||
| 472 | { | ||
| 473 | struct f11_2d_sensor_query *query = &sensor->sens_query; | ||
| 474 | struct f11_2d_data *data = &sensor->data; | ||
| 475 | int i; | ||
| 476 | |||
| 477 | sensor->nbr_fingers = (query->number_of_fingers == 5 ? 10 : | ||
| 478 | query->number_of_fingers + 1); | ||
| 479 | |||
| 480 | sensor->pkt_size = F11_CEIL(sensor->nbr_fingers, 4); | ||
| 481 | |||
| 482 | if (query->has_abs) | ||
| 483 | sensor->pkt_size += (sensor->nbr_fingers * 5); | ||
| 484 | |||
| 485 | if (query->has_rel) | ||
| 486 | sensor->pkt_size += (sensor->nbr_fingers * 2); | ||
| 487 | |||
| 488 | /* Check if F11_2D_Query7 is non-zero */ | ||
| 489 | if (query->f11_2d_query7__8[0]) | ||
| 490 | sensor->pkt_size += sizeof(u8); | ||
| 491 | |||
| 492 | /* Check if F11_2D_Query7 or F11_2D_Query8 is non-zero */ | ||
| 493 | if (query->f11_2d_query7__8[0] || query->f11_2d_query7__8[1]) | ||
| 494 | sensor->pkt_size += sizeof(u8); | ||
| 495 | |||
| 496 | if (query->has_pinch || query->has_flick || query->has_rotate) { | ||
| 497 | sensor->pkt_size += 3; | ||
| 498 | if (!query->has_flick) | ||
| 499 | sensor->pkt_size--; | ||
| 500 | if (!query->has_rotate) | ||
| 501 | sensor->pkt_size--; | ||
| 502 | } | ||
| 503 | |||
| 504 | if (query->has_touch_shapes) | ||
| 505 | sensor->pkt_size += F11_CEIL(query->nbr_touch_shapes + 1, 8); | ||
| 506 | |||
| 507 | sensor->data_pkt = kzalloc(sensor->pkt_size, GFP_KERNEL); | ||
| 508 | if (!sensor->data_pkt) | ||
| 509 | return -ENOMEM; | ||
| 510 | |||
| 511 | data->f_state = (struct f11_2d_data_0 *)sensor->data_pkt; | ||
| 512 | i = F11_CEIL(sensor->nbr_fingers, 4); | ||
| 513 | |||
| 514 | if (query->has_abs) { | ||
| 515 | data->abs_pos = (struct f11_2d_data_1_5 *) | ||
| 516 | &sensor->data_pkt[i]; | ||
| 517 | i += (sensor->nbr_fingers * 5); | ||
| 518 | } | ||
| 519 | |||
| 520 | if (query->has_rel) { | ||
| 521 | data->rel_pos = (struct f11_2d_data_6_7 *) | ||
| 522 | &sensor->data_pkt[i]; | ||
| 523 | i += (sensor->nbr_fingers * 2); | ||
| 524 | } | ||
| 525 | |||
| 526 | if (query->f11_2d_query7__8[0]) { | ||
| 527 | data->gest_1 = (struct f11_2d_data_8 *)&sensor->data_pkt[i]; | ||
| 528 | i++; | ||
| 529 | } | ||
| 530 | |||
| 531 | if (query->f11_2d_query7__8[0] || query->f11_2d_query7__8[1]) { | ||
| 532 | data->gest_2 = (struct f11_2d_data_9 *)&sensor->data_pkt[i]; | ||
| 533 | i++; | ||
| 534 | } | ||
| 535 | |||
| 536 | if (query->has_pinch) { | ||
| 537 | data->pinch = (struct f11_2d_data_10 *)&sensor->data_pkt[i]; | ||
| 538 | i++; | ||
| 539 | } | ||
| 540 | |||
| 541 | if (query->has_flick) { | ||
| 542 | if (query->has_pinch) { | ||
| 543 | data->flick = (struct f11_2d_data_10_12 *)data->pinch; | ||
| 544 | i += 2; | ||
| 545 | } else { | ||
| 546 | data->flick = (struct f11_2d_data_10_12 *) | ||
| 547 | &sensor->data_pkt[i]; | ||
| 548 | i += 3; | ||
| 549 | } | ||
| 550 | } | ||
| 551 | |||
| 552 | if (query->has_rotate) { | ||
| 553 | if (query->has_flick) { | ||
| 554 | data->rotate = (struct f11_2d_data_11_12 *) | ||
| 555 | (data->flick + 1); | ||
| 556 | } else { | ||
| 557 | data->rotate = (struct f11_2d_data_11_12 *) | ||
| 558 | &sensor->data_pkt[i]; | ||
| 559 | i += 2; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | if (query->has_touch_shapes) | ||
| 564 | data->shapes = (struct f11_2d_data_13 *)&sensor->data_pkt[i]; | ||
| 565 | |||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | static int rmi_f11_read_control_parameters(struct rmi_device *rmi_dev, | ||
| 570 | struct f11_2d_device_query *query, | ||
| 571 | struct rmi_f11_2d_ctrl *ctrl, | ||
| 572 | int ctrl_base_addr) { | ||
| 573 | int read_address = ctrl_base_addr; | ||
| 574 | int error = 0; | ||
| 575 | |||
| 576 | if (ctrl->ctrl0) { | ||
| 577 | error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl0->reg, | ||
| 578 | sizeof(union rmi_f11_2d_ctrl0)); | ||
| 579 | if (error < 0) { | ||
| 580 | dev_err(&rmi_dev->dev, | ||
| 581 | "Failed to read F11 ctrl0, code: %d.\n", error); | ||
| 582 | return error; | ||
| 583 | } | ||
| 584 | read_address = read_address + sizeof(union rmi_f11_2d_ctrl0); | ||
| 585 | } | ||
| 586 | |||
| 587 | if (ctrl->ctrl1) { | ||
| 588 | error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl1->reg, | ||
| 589 | sizeof(union rmi_f11_2d_ctrl1)); | ||
| 590 | if (error < 0) { | ||
| 591 | dev_err(&rmi_dev->dev, | ||
| 592 | "Failed to read F11 ctrl1, code: %d.\n", error); | ||
| 593 | return error; | ||
| 594 | } | ||
| 595 | read_address = read_address + sizeof(union rmi_f11_2d_ctrl1); | ||
| 596 | } | ||
| 597 | |||
| 598 | if (ctrl->ctrl2__3) { | ||
| 599 | error = rmi_read_block(rmi_dev, read_address, | ||
| 600 | ctrl->ctrl2__3->regs, | ||
| 601 | sizeof(ctrl->ctrl2__3->regs)); | ||
| 602 | if (error < 0) { | ||
| 603 | dev_err(&rmi_dev->dev, | ||
| 604 | "Failed to read F11 ctrl2__3, code: %d.\n", | ||
| 605 | error); | ||
| 606 | return error; | ||
| 607 | } | ||
| 608 | read_address = read_address + sizeof(ctrl->ctrl2__3->regs); | ||
| 609 | } | ||
| 610 | |||
| 611 | if (ctrl->ctrl4) { | ||
| 612 | error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl4->reg, | ||
| 613 | sizeof(ctrl->ctrl4->reg)); | ||
| 614 | if (error < 0) { | ||
| 615 | dev_err(&rmi_dev->dev, | ||
| 616 | "Failed to read F11 ctrl4, code: %d.\n", error); | ||
| 617 | return error; | ||
| 618 | } | ||
| 619 | read_address = read_address + sizeof(ctrl->ctrl4->reg); | ||
| 620 | } | ||
| 621 | |||
| 622 | if (ctrl->ctrl5) { | ||
| 623 | error = rmi_read_block(rmi_dev, read_address, &ctrl->ctrl5->reg, | ||
| 624 | sizeof(ctrl->ctrl5->reg)); | ||
| 625 | if (error < 0) { | ||
| 626 | dev_err(&rmi_dev->dev, | ||
| 627 | "Failed to read F11 ctrl5, code: %d.\n", error); | ||
| 628 | return error; | ||
| 629 | } | ||
| 630 | read_address = read_address + sizeof(ctrl->ctrl5->reg); | ||
| 631 | } | ||
| 632 | |||
| 633 | if (ctrl->ctrl6__7) { | ||
| 634 | error = rmi_read_block(rmi_dev, read_address, | ||
| 635 | ctrl->ctrl6__7->regs, | ||
| 636 | sizeof(ctrl->ctrl6__7->regs)); | ||
| 637 | if (error < 0) { | ||
| 638 | dev_err(&rmi_dev->dev, | ||
| 639 | "Failed to read F11 ctrl6__7, code: %d.\n", | ||
| 640 | error); | ||
| 641 | return error; | ||
| 642 | } | ||
| 643 | read_address = read_address + sizeof(ctrl->ctrl6__7->regs); | ||
| 644 | } | ||
| 645 | |||
| 646 | if (ctrl->ctrl8__9) { | ||
| 647 | error = rmi_read_block(rmi_dev, read_address, | ||
| 648 | ctrl->ctrl8__9->regs, | ||
| 649 | sizeof(ctrl->ctrl8__9->regs)); | ||
| 650 | if (error < 0) { | ||
| 651 | dev_err(&rmi_dev->dev, | ||
| 652 | "Failed to read F11 ctrl8__9, code: %d.\n", | ||
| 653 | error); | ||
| 654 | return error; | ||
| 655 | } | ||
| 656 | read_address = read_address + sizeof(ctrl->ctrl8__9->regs); | ||
| 657 | } | ||
| 658 | |||
| 659 | return 0; | ||
| 660 | } | ||
| 661 | |||
| 662 | static int rmi_f11_initialize_control_parameters(struct rmi_device *rmi_dev, | ||
| 663 | struct f11_2d_device_query *query, | ||
| 664 | struct rmi_f11_2d_ctrl *ctrl, | ||
| 665 | int ctrl_base_addr) { | ||
| 666 | int error = 0; | ||
| 667 | |||
| 668 | ctrl->ctrl0 = kzalloc(sizeof(union rmi_f11_2d_ctrl0), GFP_KERNEL); | ||
| 669 | if (!ctrl->ctrl0) { | ||
| 670 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl0.\n"); | ||
| 671 | error = -ENOMEM; | ||
| 672 | goto error_exit; | ||
| 673 | } | ||
| 674 | |||
| 675 | ctrl->ctrl1 = kzalloc(sizeof(union rmi_f11_2d_ctrl1), GFP_KERNEL); | ||
| 676 | if (!ctrl->ctrl1) { | ||
| 677 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl1.\n"); | ||
| 678 | error = -ENOMEM; | ||
| 679 | goto error_exit; | ||
| 680 | } | ||
| 681 | |||
| 682 | ctrl->ctrl2__3 = kzalloc(sizeof(union rmi_f11_2d_ctrl2__3), GFP_KERNEL); | ||
| 683 | if (!ctrl->ctrl2__3) { | ||
| 684 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl2__3.\n"); | ||
| 685 | error = -ENOMEM; | ||
| 686 | goto error_exit; | ||
| 687 | } | ||
| 688 | |||
| 689 | ctrl->ctrl4 = kzalloc(sizeof(union rmi_f11_2d_ctrl4), GFP_KERNEL); | ||
| 690 | if (!ctrl->ctrl4) { | ||
| 691 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl4.\n"); | ||
| 692 | error = -ENOMEM; | ||
| 693 | goto error_exit; | ||
| 694 | } | ||
| 695 | |||
| 696 | ctrl->ctrl5 = kzalloc(sizeof(union rmi_f11_2d_ctrl5), GFP_KERNEL); | ||
| 697 | if (!ctrl->ctrl5) { | ||
| 698 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl5.\n"); | ||
| 699 | error = -ENOMEM; | ||
| 700 | goto error_exit; | ||
| 701 | } | ||
| 702 | |||
| 703 | ctrl->ctrl6__7 = kzalloc(sizeof(union rmi_f11_2d_ctrl6__7), GFP_KERNEL); | ||
| 704 | if (!ctrl->ctrl6__7) { | ||
| 705 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl6__7.\n"); | ||
| 706 | error = -ENOMEM; | ||
| 707 | goto error_exit; | ||
| 708 | } | ||
| 709 | |||
| 710 | ctrl->ctrl8__9 = kzalloc(sizeof(union rmi_f11_2d_ctrl8__9), GFP_KERNEL); | ||
| 711 | if (!ctrl->ctrl8__9) { | ||
| 712 | dev_err(&rmi_dev->dev, "Failed to allocate F11 ctrl8__9.\n"); | ||
| 713 | error = -ENOMEM; | ||
| 714 | goto error_exit; | ||
| 715 | } | ||
| 716 | |||
| 717 | return rmi_f11_read_control_parameters(rmi_dev, query, | ||
| 718 | ctrl, ctrl_base_addr); | ||
| 719 | |||
| 720 | error_exit: | ||
| 721 | kfree(ctrl->ctrl0); | ||
| 722 | kfree(ctrl->ctrl1); | ||
| 723 | kfree(ctrl->ctrl2__3); | ||
| 724 | kfree(ctrl->ctrl4); | ||
| 725 | kfree(ctrl->ctrl5); | ||
| 726 | kfree(ctrl->ctrl6__7); | ||
| 727 | kfree(ctrl->ctrl8__9); | ||
| 728 | |||
| 729 | return error; | ||
| 730 | } | ||
| 731 | |||
| 732 | static inline int rmi_f11_set_control_parameters(struct rmi_device *rmi_dev, | ||
| 733 | struct f11_2d_sensor_query *query, | ||
| 734 | struct rmi_f11_2d_ctrl *ctrl, | ||
| 735 | int ctrl_base_addr) | ||
| 736 | { | ||
| 737 | int write_address = ctrl_base_addr; | ||
| 738 | int error; | ||
| 739 | |||
| 740 | if (ctrl->ctrl0) { | ||
| 741 | error = rmi_write_block(rmi_dev, write_address, | ||
| 742 | &ctrl->ctrl0->reg, | ||
| 743 | 1); | ||
| 744 | if (error < 0) | ||
| 745 | return error; | ||
| 746 | write_address++; | ||
| 747 | } | ||
| 748 | |||
| 749 | if (ctrl->ctrl1) { | ||
| 750 | error = rmi_write_block(rmi_dev, write_address, | ||
| 751 | &ctrl->ctrl1->reg, | ||
| 752 | 1); | ||
| 753 | if (error < 0) | ||
| 754 | return error; | ||
| 755 | write_address++; | ||
| 756 | } | ||
| 757 | |||
| 758 | if (ctrl->ctrl2__3) { | ||
| 759 | error = rmi_write_block(rmi_dev, write_address, | ||
| 760 | ctrl->ctrl2__3->regs, | ||
| 761 | sizeof(ctrl->ctrl2__3->regs)); | ||
| 762 | if (error < 0) | ||
| 763 | return error; | ||
| 764 | write_address += sizeof(ctrl->ctrl2__3->regs); | ||
| 765 | } | ||
| 766 | |||
| 767 | if (ctrl->ctrl4) { | ||
| 768 | error = rmi_write_block(rmi_dev, write_address, | ||
| 769 | &ctrl->ctrl4->reg, | ||
| 770 | 1); | ||
| 771 | if (error < 0) | ||
| 772 | return error; | ||
| 773 | write_address++; | ||
| 774 | } | ||
| 775 | |||
| 776 | if (ctrl->ctrl5) { | ||
| 777 | error = rmi_write_block(rmi_dev, write_address, | ||
| 778 | &ctrl->ctrl5->reg, | ||
| 779 | 1); | ||
| 780 | if (error < 0) | ||
| 781 | return error; | ||
| 782 | write_address++; | ||
| 783 | } | ||
| 784 | |||
| 785 | if (ctrl->ctrl6__7) { | ||
| 786 | error = rmi_write_block(rmi_dev, write_address, | ||
| 787 | &ctrl->ctrl6__7->regs[0], | ||
| 788 | sizeof(ctrl->ctrl6__7->regs)); | ||
| 789 | if (error < 0) | ||
| 790 | return error; | ||
| 791 | write_address += sizeof(ctrl->ctrl6__7->regs); | ||
| 792 | } | ||
| 793 | |||
| 794 | if (ctrl->ctrl8__9) { | ||
| 795 | error = rmi_write_block(rmi_dev, write_address, | ||
| 796 | &ctrl->ctrl8__9->regs[0], | ||
| 797 | sizeof(ctrl->ctrl8__9->regs)); | ||
| 798 | if (error < 0) | ||
| 799 | return error; | ||
| 800 | write_address += sizeof(ctrl->ctrl8__9->regs); | ||
| 801 | } | ||
| 802 | |||
| 803 | if (ctrl->ctrl10) { | ||
| 804 | error = rmi_write_block(rmi_dev, write_address, | ||
| 805 | &ctrl->ctrl10->reg, | ||
| 806 | 1); | ||
| 807 | if (error < 0) | ||
| 808 | return error; | ||
| 809 | write_address++; | ||
| 810 | } | ||
| 811 | |||
| 812 | if (ctrl->ctrl11) { | ||
| 813 | error = rmi_write_block(rmi_dev, write_address, | ||
| 814 | &ctrl->ctrl11->reg, | ||
| 815 | 1); | ||
| 816 | if (error < 0) | ||
| 817 | return error; | ||
| 818 | write_address++; | ||
| 819 | } | ||
| 820 | |||
| 821 | if (ctrl->ctrl12 && ctrl->ctrl12_size && query->configurable) { | ||
| 822 | if (ctrl->ctrl12_size > query->max_electrodes) { | ||
| 823 | dev_err(&rmi_dev->dev, | ||
| 824 | "%s: invalid cfg size:%d, should be < %d.\n", | ||
| 825 | __func__, ctrl->ctrl12_size, | ||
| 826 | query->max_electrodes); | ||
| 827 | return -EINVAL; | ||
| 828 | } | ||
| 829 | error = rmi_write_block(rmi_dev, write_address, | ||
| 830 | &ctrl->ctrl12->reg, | ||
| 831 | ctrl->ctrl12_size); | ||
| 832 | if (error < 0) | ||
| 833 | return error; | ||
| 834 | write_address += ctrl->ctrl12_size; | ||
| 835 | } | ||
| 836 | |||
| 837 | if (ctrl->ctrl14) { | ||
| 838 | error = rmi_write_block(rmi_dev, | ||
| 839 | write_address, | ||
| 840 | &ctrl->ctrl0->reg, | ||
| 841 | 1); | ||
| 842 | if (error < 0) | ||
| 843 | return error; | ||
| 844 | write_address++; | ||
| 845 | } | ||
| 846 | |||
| 847 | if (ctrl->ctrl15) { | ||
| 848 | error = rmi_write_block(rmi_dev, write_address, | ||
| 849 | ctrl->ctrl15, | ||
| 850 | 1); | ||
| 851 | if (error < 0) | ||
| 852 | return error; | ||
| 853 | write_address++; | ||
| 854 | } | ||
| 855 | |||
| 856 | if (ctrl->ctrl16) { | ||
| 857 | error = rmi_write_block(rmi_dev, write_address, | ||
| 858 | ctrl->ctrl16, | ||
| 859 | 1); | ||
| 860 | if (error < 0) | ||
| 861 | return error; | ||
| 862 | write_address++; | ||
| 863 | } | ||
| 864 | |||
| 865 | if (ctrl->ctrl17) { | ||
| 866 | error = rmi_write_block(rmi_dev, write_address, | ||
| 867 | ctrl->ctrl17, | ||
| 868 | 1); | ||
| 869 | if (error < 0) | ||
| 870 | return error; | ||
| 871 | write_address++; | ||
| 872 | } | ||
| 873 | |||
| 874 | if (ctrl->ctrl18) { | ||
| 875 | error = rmi_write_block(rmi_dev, write_address, | ||
| 876 | ctrl->ctrl18, | ||
| 877 | 1); | ||
| 878 | if (error < 0) | ||
| 879 | return error; | ||
| 880 | write_address++; | ||
| 881 | } | ||
| 882 | |||
| 883 | if (ctrl->ctrl19) { | ||
| 884 | error = rmi_write_block(rmi_dev, write_address, | ||
| 885 | ctrl->ctrl19, | ||
| 886 | 1); | ||
| 887 | if (error < 0) | ||
| 888 | return error; | ||
| 889 | write_address++; | ||
| 890 | } | ||
| 891 | |||
| 892 | return 0; | ||
| 893 | } | ||
| 894 | |||
| 895 | static inline int rmi_f11_get_query_parameters(struct rmi_device *rmi_dev, | ||
| 896 | struct f11_2d_sensor_query *query, u8 query_base_addr) | ||
| 897 | { | ||
| 898 | int query_size; | ||
| 899 | int rc; | ||
| 900 | |||
| 901 | rc = rmi_read_block(rmi_dev, query_base_addr, query->f11_2d_query1__4, | ||
| 902 | sizeof(query->f11_2d_query1__4)); | ||
| 903 | if (rc < 0) | ||
| 904 | return rc; | ||
| 905 | query_size = rc; | ||
| 906 | |||
| 907 | if (query->has_abs) { | ||
| 908 | rc = rmi_read(rmi_dev, query_base_addr + query_size, | ||
| 909 | &query->f11_2d_query5); | ||
| 910 | if (rc < 0) | ||
| 911 | return rc; | ||
| 912 | query_size++; | ||
| 913 | } | ||
| 914 | |||
| 915 | if (query->has_rel) { | ||
| 916 | rc = rmi_read(rmi_dev, query_base_addr + query_size, | ||
| 917 | &query->f11_2d_query6); | ||
| 918 | if (rc < 0) | ||
| 919 | return rc; | ||
| 920 | query_size++; | ||
| 921 | } | ||
| 922 | |||
| 923 | if (query->has_gestures) { | ||
| 924 | rc = rmi_read_block(rmi_dev, query_base_addr + query_size, | ||
| 925 | query->f11_2d_query7__8, | ||
| 926 | sizeof(query->f11_2d_query7__8)); | ||
| 927 | if (rc < 0) | ||
| 928 | return rc; | ||
| 929 | query_size += sizeof(query->f11_2d_query7__8); | ||
| 930 | } | ||
| 931 | |||
| 932 | if (query->has_touch_shapes) { | ||
| 933 | rc = rmi_read(rmi_dev, query_base_addr + query_size, | ||
| 934 | &query->f11_2d_query10); | ||
| 935 | if (rc < 0) | ||
| 936 | return rc; | ||
| 937 | query_size++; | ||
| 938 | } | ||
| 939 | |||
| 940 | return query_size; | ||
| 941 | } | ||
| 942 | |||
| 943 | /* This operation is done in a number of places, so we have a handy routine | ||
| 944 | * for it. | ||
| 945 | */ | ||
| 946 | static void f11_set_abs_params(struct rmi_function_container *fc, int index) | ||
| 947 | { | ||
| 948 | struct f11_data *instance_data = fc->data; | ||
| 949 | struct input_dev *input = instance_data->sensors[index].input; | ||
| 950 | int device_x_max = | ||
| 951 | instance_data->dev_controls.ctrl6__7->sensor_max_x_pos; | ||
| 952 | int device_y_max = | ||
| 953 | instance_data->dev_controls.ctrl8__9->sensor_max_y_pos; | ||
| 954 | int x_min, x_max, y_min, y_max; | ||
| 955 | |||
| 956 | if (instance_data->sensors[index].axis_align.swap_axes) { | ||
| 957 | int temp = device_x_max; | ||
| 958 | device_x_max = device_y_max; | ||
| 959 | device_y_max = temp; | ||
| 960 | } | ||
| 961 | |||
| 962 | /* Use the max X and max Y read from the device, or the clip values, | ||
| 963 | * whichever is stricter. | ||
| 964 | */ | ||
| 965 | x_min = instance_data->sensors[index].axis_align.clip_X_low; | ||
| 966 | if (instance_data->sensors[index].axis_align.clip_X_high) | ||
| 967 | x_max = min((int) device_x_max, | ||
| 968 | instance_data->sensors[index].axis_align.clip_X_high); | ||
| 969 | else | ||
| 970 | x_max = device_x_max; | ||
| 971 | |||
| 972 | y_min = instance_data->sensors[index].axis_align.clip_Y_low; | ||
| 973 | if (instance_data->sensors[index].axis_align.clip_Y_high) | ||
| 974 | y_max = min((int) device_y_max, | ||
| 975 | instance_data->sensors[index].axis_align.clip_Y_high); | ||
| 976 | else | ||
| 977 | y_max = device_y_max; | ||
| 978 | |||
| 979 | dev_dbg(&fc->dev, "Set ranges X=[%d..%d] Y=[%d..%d].", | ||
| 980 | x_min, x_max, y_min, y_max); | ||
| 981 | |||
| 982 | #ifdef ABS_MT_PRESSURE | ||
| 983 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, | ||
| 984 | DEFAULT_MAX_ABS_MT_PRESSURE, 0, 0); | ||
| 985 | #endif | ||
| 986 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, | ||
| 987 | 0, DEFAULT_MAX_ABS_MT_TOUCH, 0, 0); | ||
| 988 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, | ||
| 989 | 0, DEFAULT_MAX_ABS_MT_TOUCH, 0, 0); | ||
| 990 | input_set_abs_params(input, ABS_MT_ORIENTATION, | ||
| 991 | 0, DEFAULT_MAX_ABS_MT_ORIENTATION, 0, 0); | ||
| 992 | input_set_abs_params(input, ABS_MT_TRACKING_ID, | ||
| 993 | DEFAULT_MIN_ABS_MT_TRACKING_ID, | ||
| 994 | DEFAULT_MAX_ABS_MT_TRACKING_ID, 0, 0); | ||
| 995 | /* TODO get max_x_pos (and y) from control registers. */ | ||
| 996 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
| 997 | x_min, x_max, 0, 0); | ||
| 998 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
| 999 | y_min, y_max, 0, 0); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | static int rmi_f11_init(struct rmi_function_container *fc) | ||
| 1003 | { | ||
| 1004 | struct rmi_device *rmi_dev = fc->rmi_dev; | ||
| 1005 | struct rmi_device_platform_data *pdata; | ||
| 1006 | struct f11_data *f11; | ||
| 1007 | struct input_dev *input_dev; | ||
| 1008 | struct input_dev *input_dev_mouse; | ||
| 1009 | u8 query_offset; | ||
| 1010 | u8 query_base_addr; | ||
| 1011 | u8 control_base_addr; | ||
| 1012 | u16 max_x_pos, max_y_pos, temp; | ||
| 1013 | int rc; | ||
| 1014 | int i; | ||
| 1015 | int retval = 0; | ||
| 1016 | int attr_count = 0; | ||
| 1017 | |||
| 1018 | dev_info(&fc->dev, "Intializing F11 values."); | ||
| 1019 | |||
| 1020 | /* | ||
| 1021 | ** init instance data, fill in values and create any sysfs files | ||
| 1022 | */ | ||
| 1023 | f11 = kzalloc(sizeof(struct f11_data), GFP_KERNEL); | ||
| 1024 | if (!f11) | ||
| 1025 | return -ENOMEM; | ||
| 1026 | fc->data = f11; | ||
| 1027 | |||
| 1028 | query_base_addr = fc->fd.query_base_addr; | ||
| 1029 | control_base_addr = fc->fd.control_base_addr; | ||
| 1030 | |||
| 1031 | rc = rmi_read(rmi_dev, query_base_addr, &f11->dev_query.f11_2d_query0); | ||
| 1032 | if (rc < 0) | ||
| 1033 | goto err_free_data; | ||
| 1034 | |||
| 1035 | rc = rmi_f11_initialize_control_parameters(rmi_dev, &f11->dev_query, | ||
| 1036 | &f11->dev_controls, control_base_addr); | ||
| 1037 | if (rc < 0) { | ||
| 1038 | dev_err(&fc->dev, | ||
| 1039 | "Failed to initialize F11 control params.\n"); | ||
| 1040 | goto err_free_data; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | query_offset = (query_base_addr + 1); | ||
| 1044 | /* Increase with one since number of sensors is zero based */ | ||
| 1045 | for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) { | ||
| 1046 | f11->sensors[i].sensor_index = i; | ||
| 1047 | |||
| 1048 | rc = rmi_f11_get_query_parameters(rmi_dev, | ||
| 1049 | &f11->sensors[i].sens_query, | ||
| 1050 | query_offset); | ||
| 1051 | if (rc < 0) | ||
| 1052 | goto err_free_data; | ||
| 1053 | |||
| 1054 | query_offset += rc; | ||
| 1055 | |||
| 1056 | pdata = to_rmi_platform_data(rmi_dev); | ||
| 1057 | if (pdata) | ||
| 1058 | f11->sensors[i].axis_align = pdata->axis_align; | ||
| 1059 | |||
| 1060 | if (pdata && pdata->f11_ctrl) { | ||
| 1061 | rc = rmi_f11_set_control_parameters(rmi_dev, | ||
| 1062 | &f11->sensors[i].sens_query, | ||
| 1063 | pdata->f11_ctrl, | ||
| 1064 | control_base_addr); | ||
| 1065 | if (rc < 0) | ||
| 1066 | goto err_free_data; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | if (pdata && pdata->f11_ctrl && | ||
| 1070 | pdata->f11_ctrl->ctrl6__7 && | ||
| 1071 | pdata->f11_ctrl->ctrl8__9) { | ||
| 1072 | max_x_pos = pdata->f11_ctrl->ctrl6__7->sensor_max_x_pos; | ||
| 1073 | max_y_pos = pdata->f11_ctrl->ctrl8__9->sensor_max_y_pos; | ||
| 1074 | |||
| 1075 | } else { | ||
| 1076 | rc = rmi_read_block(rmi_dev, | ||
| 1077 | control_base_addr + F11_CTRL_SENSOR_MAX_X_POS_OFFSET, | ||
| 1078 | (u8 *)&max_x_pos, sizeof(max_x_pos)); | ||
| 1079 | if (rc < 0) | ||
| 1080 | goto err_free_data; | ||
| 1081 | |||
| 1082 | rc = rmi_read_block(rmi_dev, | ||
| 1083 | control_base_addr + F11_CTRL_SENSOR_MAX_Y_POS_OFFSET, | ||
| 1084 | (u8 *)&max_y_pos, sizeof(max_y_pos)); | ||
| 1085 | if (rc < 0) | ||
| 1086 | goto err_free_data; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | if (pdata->axis_align.swap_axes) { | ||
| 1090 | temp = max_x_pos; | ||
| 1091 | max_x_pos = max_y_pos; | ||
| 1092 | max_y_pos = temp; | ||
| 1093 | } | ||
| 1094 | f11->sensors[i].max_x = max_x_pos; | ||
| 1095 | f11->sensors[i].max_y = max_y_pos; | ||
| 1096 | |||
| 1097 | rc = rmi_f11_2d_construct_data(&f11->sensors[i]); | ||
| 1098 | if (rc < 0) | ||
| 1099 | goto err_free_data; | ||
| 1100 | |||
| 1101 | input_dev = input_allocate_device(); | ||
| 1102 | if (!input_dev) { | ||
| 1103 | rc = -ENOMEM; | ||
| 1104 | goto err_free_data; | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | f11->sensors[i].input = input_dev; | ||
| 1108 | /* TODO how to modify the dev name and | ||
| 1109 | * phys name for input device */ | ||
| 1110 | sprintf(f11->sensors[i].input_name, "%sfn%02x", | ||
| 1111 | dev_name(&rmi_dev->dev), fc->fd.function_number); | ||
| 1112 | input_dev->name = f11->sensors[i].input_name; | ||
| 1113 | sprintf(f11->sensors[i].input_phys, "%s/input0", | ||
| 1114 | input_dev->name); | ||
| 1115 | input_dev->phys = f11->sensors[i].input_phys; | ||
| 1116 | input_dev->dev.parent = &rmi_dev->dev; | ||
| 1117 | input_set_drvdata(input_dev, f11); | ||
| 1118 | |||
| 1119 | set_bit(EV_SYN, input_dev->evbit); | ||
| 1120 | set_bit(EV_KEY, input_dev->evbit); | ||
| 1121 | set_bit(EV_ABS, input_dev->evbit); | ||
| 1122 | |||
| 1123 | f11_set_abs_params(fc, i); | ||
| 1124 | |||
| 1125 | dev_dbg(&fc->dev, "%s: Sensor %d hasRel %d.\n", | ||
| 1126 | __func__, i, f11->sensors[i].sens_query.has_rel); | ||
| 1127 | if (f11->sensors[i].sens_query.has_rel) { | ||
| 1128 | set_bit(EV_REL, input_dev->evbit); | ||
| 1129 | set_bit(REL_X, input_dev->relbit); | ||
| 1130 | set_bit(REL_Y, input_dev->relbit); | ||
| 1131 | } | ||
| 1132 | rc = input_register_device(input_dev); | ||
| 1133 | if (rc < 0) | ||
| 1134 | goto err_free_input; | ||
| 1135 | |||
| 1136 | if (f11->sensors[i].sens_query.has_rel) { | ||
| 1137 | /*create input device for mouse events */ | ||
| 1138 | input_dev_mouse = input_allocate_device(); | ||
| 1139 | if (!input_dev_mouse) { | ||
| 1140 | rc = -ENOMEM; | ||
| 1141 | goto err_free_data; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | f11->sensors[i].mouse_input = input_dev_mouse; | ||
| 1145 | input_dev_mouse->name = "rmi_mouse"; | ||
| 1146 | input_dev_mouse->phys = "rmi_f11/input0"; | ||
| 1147 | |||
| 1148 | input_dev_mouse->id.vendor = 0x18d1; | ||
| 1149 | input_dev_mouse->id.product = 0x0210; | ||
| 1150 | input_dev_mouse->id.version = 0x0100; | ||
| 1151 | |||
| 1152 | set_bit(EV_REL, input_dev_mouse->evbit); | ||
| 1153 | set_bit(REL_X, input_dev_mouse->relbit); | ||
| 1154 | set_bit(REL_Y, input_dev_mouse->relbit); | ||
| 1155 | |||
| 1156 | set_bit(BTN_MOUSE, input_dev_mouse->evbit); | ||
| 1157 | /* Register device's buttons and keys */ | ||
| 1158 | set_bit(EV_KEY, input_dev_mouse->evbit); | ||
| 1159 | set_bit(BTN_LEFT, input_dev_mouse->keybit); | ||
| 1160 | set_bit(BTN_MIDDLE, input_dev_mouse->keybit); | ||
| 1161 | set_bit(BTN_RIGHT, input_dev_mouse->keybit); | ||
| 1162 | |||
| 1163 | rc = input_register_device(input_dev_mouse); | ||
| 1164 | if (rc < 0) | ||
| 1165 | goto err_free_input; | ||
| 1166 | set_bit(BTN_RIGHT, input_dev_mouse->keybit); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | } | ||
| 1170 | |||
| 1171 | dev_info(&fc->dev, "Creating sysfs files."); | ||
| 1172 | dev_dbg(&fc->dev, "Creating fn11 sysfs files."); | ||
| 1173 | |||
| 1174 | /* Set up sysfs device attributes. */ | ||
| 1175 | for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { | ||
| 1176 | if (sysfs_create_file | ||
| 1177 | (&fc->dev.kobj, &attrs[attr_count].attr) < 0) { | ||
| 1178 | dev_err(&fc->dev, "Failed to create sysfs file for %s.", | ||
| 1179 | attrs[attr_count].attr.name); | ||
| 1180 | retval = -ENODEV; | ||
| 1181 | goto err_free_input; | ||
| 1182 | } | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | dev_info(&fc->dev, "Done Creating fn11 sysfs files."); | ||
| 1186 | return 0; | ||
| 1187 | |||
| 1188 | err_free_input: | ||
| 1189 | for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) { | ||
| 1190 | if (f11->sensors[i].input) | ||
| 1191 | input_free_device(f11->sensors[i].input); | ||
| 1192 | if (f11->sensors[i].sens_query.has_rel && | ||
| 1193 | f11->sensors[i].mouse_input) | ||
| 1194 | input_free_device(f11->sensors[i].mouse_input); | ||
| 1195 | } | ||
| 1196 | err_free_data: | ||
| 1197 | for (attr_count--; attr_count >= 0; attr_count--) | ||
| 1198 | device_remove_file(&fc->rmi_dev->dev, &attrs[attr_count]); | ||
| 1199 | |||
| 1200 | kfree(f11); | ||
| 1201 | return rc; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | int rmi_f11_attention(struct rmi_function_container *fc, u8 *irq_bits) | ||
| 1205 | { | ||
| 1206 | struct rmi_device *rmi_dev = fc->rmi_dev; | ||
| 1207 | struct f11_data *f11 = fc->data; | ||
| 1208 | u8 data_base_addr = fc->fd.data_base_addr; | ||
| 1209 | int data_base_addr_offset = 0; | ||
| 1210 | int error; | ||
| 1211 | int i; | ||
| 1212 | |||
| 1213 | for (i = 0; i < f11->dev_query.nbr_of_sensors + 1; i++) { | ||
| 1214 | error = rmi_read_block(rmi_dev, | ||
| 1215 | data_base_addr + data_base_addr_offset, | ||
| 1216 | f11->sensors[i].data_pkt, | ||
| 1217 | f11->sensors[i].pkt_size); | ||
| 1218 | if (error < 0) | ||
| 1219 | return error; | ||
| 1220 | |||
| 1221 | rmi_f11_finger_handler(&f11->sensors[i]); | ||
| 1222 | data_base_addr_offset += f11->sensors[i].pkt_size; | ||
| 1223 | } | ||
| 1224 | return 0; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | static void rmi_f11_remove(struct rmi_function_container *fc) | ||
| 1228 | { | ||
| 1229 | struct f11_data *data = fc->data; | ||
| 1230 | int i; | ||
| 1231 | |||
| 1232 | for (i = 0; i < (data->dev_query.nbr_of_sensors + 1); i++) { | ||
| 1233 | input_unregister_device(data->sensors[i].input); | ||
| 1234 | if (data->sensors[i].sens_query.has_rel) | ||
| 1235 | input_unregister_device(data->sensors[i].mouse_input); | ||
| 1236 | } | ||
| 1237 | kfree(fc->data); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | static struct rmi_function_handler function_handler = { | ||
| 1241 | .func = 0x11, | ||
| 1242 | .init = rmi_f11_init, | ||
| 1243 | .attention = rmi_f11_attention, | ||
| 1244 | .remove = rmi_f11_remove | ||
| 1245 | }; | ||
| 1246 | |||
| 1247 | static int __init rmi_f11_module_init(void) | ||
| 1248 | { | ||
| 1249 | int error; | ||
| 1250 | |||
| 1251 | error = rmi_register_function_driver(&function_handler); | ||
| 1252 | if (error < 0) { | ||
| 1253 | pr_err("%s: register failed!\n", __func__); | ||
| 1254 | return error; | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | return 0; | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | static void __exit rmi_f11_module_exit(void) | ||
| 1261 | { | ||
| 1262 | rmi_unregister_function_driver(&function_handler); | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | static ssize_t rmi_fn_11_maxPos_show(struct device *dev, | ||
| 1266 | struct device_attribute *attr, | ||
| 1267 | char *buf) | ||
| 1268 | { | ||
| 1269 | struct rmi_function_container *fc; | ||
| 1270 | struct f11_data *data; | ||
| 1271 | |||
| 1272 | fc = to_rmi_function_container(dev); | ||
| 1273 | data = fc->data; | ||
| 1274 | |||
| 1275 | return snprintf(buf, PAGE_SIZE, "%u %u\n", | ||
| 1276 | data->sensors[0].max_x, data->sensors[0].max_y); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | static ssize_t rmi_fn_11_flip_show(struct device *dev, | ||
| 1280 | struct device_attribute *attr, | ||
| 1281 | char *buf) | ||
| 1282 | { | ||
| 1283 | struct rmi_function_container *fc; | ||
| 1284 | struct f11_data *data; | ||
| 1285 | |||
| 1286 | fc = to_rmi_function_container(dev); | ||
| 1287 | data = fc->data; | ||
| 1288 | |||
| 1289 | return snprintf(buf, PAGE_SIZE, "%u %u\n", | ||
| 1290 | data->sensors[0].axis_align.flip_x, | ||
| 1291 | data->sensors[0].axis_align.flip_y); | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | static ssize_t rmi_fn_11_flip_store(struct device *dev, | ||
| 1295 | struct device_attribute *attr, | ||
| 1296 | const char *buf, | ||
| 1297 | size_t count) | ||
| 1298 | { | ||
| 1299 | struct rmi_function_container *fc; | ||
| 1300 | struct f11_data *instance_data; | ||
| 1301 | unsigned int new_X, new_Y; | ||
| 1302 | |||
| 1303 | fc = to_rmi_function_container(dev); | ||
| 1304 | instance_data = fc->data; | ||
| 1305 | |||
| 1306 | |||
| 1307 | if (sscanf(buf, "%u %u", &new_X, &new_Y) != 2) | ||
| 1308 | return -EINVAL; | ||
| 1309 | if (new_X < 0 || new_X > 1 || new_Y < 0 || new_Y > 1) | ||
| 1310 | return -EINVAL; | ||
| 1311 | instance_data->sensors[0].axis_align.flip_x = new_X; | ||
| 1312 | instance_data->sensors[0].axis_align.flip_y = new_Y; | ||
| 1313 | |||
| 1314 | return count; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | static ssize_t rmi_fn_11_swap_show(struct device *dev, | ||
| 1318 | struct device_attribute *attr, char *buf) | ||
| 1319 | { | ||
| 1320 | struct rmi_function_container *fc; | ||
| 1321 | struct f11_data *instance_data; | ||
| 1322 | |||
| 1323 | fc = to_rmi_function_container(dev); | ||
| 1324 | instance_data = fc->data; | ||
| 1325 | |||
| 1326 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
| 1327 | instance_data->sensors[0].axis_align.swap_axes); | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | static ssize_t rmi_fn_11_swap_store(struct device *dev, | ||
| 1331 | struct device_attribute *attr, | ||
| 1332 | const char *buf, size_t count) | ||
| 1333 | { | ||
| 1334 | struct rmi_function_container *fc; | ||
| 1335 | struct f11_data *instance_data; | ||
| 1336 | unsigned int newSwap; | ||
| 1337 | |||
| 1338 | fc = to_rmi_function_container(dev); | ||
| 1339 | instance_data = fc->data; | ||
| 1340 | |||
| 1341 | |||
| 1342 | if (sscanf(buf, "%u", &newSwap) != 1) | ||
| 1343 | return -EINVAL; | ||
| 1344 | if (newSwap < 0 || newSwap > 1) | ||
| 1345 | return -EINVAL; | ||
| 1346 | instance_data->sensors[0].axis_align.swap_axes = newSwap; | ||
| 1347 | |||
| 1348 | f11_set_abs_params(fc, 0); | ||
| 1349 | |||
| 1350 | return count; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | static ssize_t rmi_fn_11_relreport_show(struct device *dev, | ||
| 1354 | struct device_attribute *attr, | ||
| 1355 | char *buf) | ||
| 1356 | { | ||
| 1357 | struct rmi_function_container *fc; | ||
| 1358 | struct f11_data *instance_data; | ||
| 1359 | |||
| 1360 | fc = to_rmi_function_container(dev); | ||
| 1361 | instance_data = fc->data; | ||
| 1362 | |||
| 1363 | return snprintf(buf, PAGE_SIZE, "%u\n", | ||
| 1364 | instance_data-> | ||
| 1365 | sensors[0].axis_align.rel_report_enabled); | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | static ssize_t rmi_fn_11_relreport_store(struct device *dev, | ||
| 1369 | struct device_attribute *attr, | ||
| 1370 | const char *buf, | ||
| 1371 | size_t count) | ||
| 1372 | { | ||
| 1373 | struct rmi_function_container *fc; | ||
| 1374 | struct f11_data *instance_data; | ||
| 1375 | unsigned int new_value; | ||
| 1376 | |||
| 1377 | fc = to_rmi_function_container(dev); | ||
| 1378 | instance_data = fc->data; | ||
| 1379 | |||
| 1380 | |||
| 1381 | if (sscanf(buf, "%u", &new_value) != 1) | ||
| 1382 | return -EINVAL; | ||
| 1383 | if (new_value < 0 || new_value > 1) | ||
| 1384 | return -EINVAL; | ||
| 1385 | instance_data->sensors[0].axis_align.rel_report_enabled = new_value; | ||
| 1386 | |||
| 1387 | return count; | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | static ssize_t rmi_fn_11_offset_show(struct device *dev, | ||
| 1391 | struct device_attribute *attr, | ||
| 1392 | char *buf) | ||
| 1393 | { | ||
| 1394 | struct rmi_function_container *fc; | ||
| 1395 | struct f11_data *instance_data; | ||
| 1396 | |||
| 1397 | fc = to_rmi_function_container(dev); | ||
| 1398 | instance_data = fc->data; | ||
| 1399 | |||
| 1400 | return snprintf(buf, PAGE_SIZE, "%d %d\n", | ||
| 1401 | instance_data->sensors[0].axis_align.offset_X, | ||
| 1402 | instance_data->sensors[0].axis_align.offset_Y); | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | static ssize_t rmi_fn_11_offset_store(struct device *dev, | ||
| 1406 | struct device_attribute *attr, | ||
| 1407 | const char *buf, | ||
| 1408 | size_t count) | ||
| 1409 | { | ||
| 1410 | struct rmi_function_container *fc; | ||
| 1411 | struct f11_data *instance_data; | ||
| 1412 | int new_X, new_Y; | ||
| 1413 | |||
| 1414 | fc = to_rmi_function_container(dev); | ||
| 1415 | instance_data = fc->data; | ||
| 1416 | |||
| 1417 | |||
| 1418 | if (sscanf(buf, "%d %d", &new_X, &new_Y) != 2) | ||
| 1419 | return -EINVAL; | ||
| 1420 | instance_data->sensors[0].axis_align.offset_X = new_X; | ||
| 1421 | instance_data->sensors[0].axis_align.offset_Y = new_Y; | ||
| 1422 | |||
| 1423 | return count; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | static ssize_t rmi_fn_11_clip_show(struct device *dev, | ||
| 1427 | struct device_attribute *attr, | ||
| 1428 | char *buf) | ||
| 1429 | { | ||
| 1430 | |||
| 1431 | struct rmi_function_container *fc; | ||
| 1432 | struct f11_data *instance_data; | ||
| 1433 | |||
| 1434 | fc = to_rmi_function_container(dev); | ||
| 1435 | instance_data = fc->data; | ||
| 1436 | |||
| 1437 | return snprintf(buf, PAGE_SIZE, "%u %u %u %u\n", | ||
| 1438 | instance_data->sensors[0].axis_align.clip_X_low, | ||
| 1439 | instance_data->sensors[0].axis_align.clip_X_high, | ||
| 1440 | instance_data->sensors[0].axis_align.clip_Y_low, | ||
| 1441 | instance_data->sensors[0].axis_align.clip_Y_high); | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | static ssize_t rmi_fn_11_clip_store(struct device *dev, | ||
| 1445 | struct device_attribute *attr, | ||
| 1446 | const char *buf, | ||
| 1447 | size_t count) | ||
| 1448 | { | ||
| 1449 | struct rmi_function_container *fc; | ||
| 1450 | struct f11_data *instance_data; | ||
| 1451 | unsigned int new_X_low, new_X_high, new_Y_low, new_Y_high; | ||
| 1452 | |||
| 1453 | fc = to_rmi_function_container(dev); | ||
| 1454 | instance_data = fc->data; | ||
| 1455 | |||
| 1456 | if (sscanf(buf, "%u %u %u %u", | ||
| 1457 | &new_X_low, &new_X_high, &new_Y_low, &new_Y_high) != 4) | ||
| 1458 | return -EINVAL; | ||
| 1459 | if (new_X_low < 0 || new_X_low >= new_X_high || new_Y_low < 0 | ||
| 1460 | || new_Y_low >= new_Y_high) | ||
| 1461 | return -EINVAL; | ||
| 1462 | instance_data->sensors[0].axis_align.clip_X_low = new_X_low; | ||
| 1463 | instance_data->sensors[0].axis_align.clip_X_high = new_X_high; | ||
| 1464 | instance_data->sensors[0].axis_align.clip_Y_low = new_Y_low; | ||
| 1465 | instance_data->sensors[0].axis_align.clip_Y_high = new_Y_high; | ||
| 1466 | |||
| 1467 | /* | ||
| 1468 | ** for now, we assume this is sensor index 0 | ||
| 1469 | */ | ||
| 1470 | f11_set_abs_params(fc, 0); | ||
| 1471 | |||
| 1472 | return count; | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | static ssize_t rmi_f11_rezero_store(struct device *dev, | ||
| 1476 | struct device_attribute *attr, | ||
| 1477 | const char *buf, size_t count) | ||
| 1478 | { | ||
| 1479 | struct rmi_function_container *fc = NULL; | ||
| 1480 | unsigned int rezero; | ||
| 1481 | int retval = 0; | ||
| 1482 | /* Command register always reads as 0, so we can just use a local. */ | ||
| 1483 | union f11_2d_commands commands = {}; | ||
| 1484 | |||
| 1485 | fc = to_rmi_function_container(dev); | ||
| 1486 | |||
| 1487 | if (sscanf(buf, "%u", &rezero) != 1) | ||
| 1488 | return -EINVAL; | ||
| 1489 | if (rezero < 0 || rezero > 1) | ||
| 1490 | return -EINVAL; | ||
| 1491 | |||
| 1492 | /* Per spec, 0 has no effect, so we skip it entirely. */ | ||
| 1493 | if (rezero) { | ||
| 1494 | commands.rezero = 1; | ||
| 1495 | retval = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr, | ||
| 1496 | &commands.reg, sizeof(commands.reg)); | ||
| 1497 | if (retval < 0) { | ||
| 1498 | dev_err(dev, "%s: failed to issue rezero command, " | ||
| 1499 | "error = %d.", __func__, retval); | ||
| 1500 | return retval; | ||
| 1501 | } | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | return count; | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | |||
| 1508 | module_init(rmi_f11_module_init); | ||
| 1509 | module_exit(rmi_f11_module_exit); | ||
| 1510 | |||
| 1511 | MODULE_AUTHOR("Stefan Nilsson <stefan.nilsson@unixphere.com>"); | ||
| 1512 | MODULE_DESCRIPTION("RMI F11 module"); | ||
| 1513 | MODULE_LICENSE("GPL"); | ||
