Lines Matching +full:trackpad +full:- +full:3 +full:x

1 // SPDX-License-Identifier: GPL-2.0+
3 * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
7 * These devices require firmware exported from a PC-based configuration tool
11 * Link to PC-based configuration tool and datasheet: https://www.azoteq.com/
48 #define IQS5XX_ALP_REATI BIT(3)
70 #define IQS5XX_CHKSM_LEN (IQS5XX_APP - IQS5XX_CHKSM)
71 #define IQS5XX_APP_LEN (IQS5XX_CSTM - IQS5XX_APP)
72 #define IQS5XX_CSTM_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM)
73 #define IQS5XX_PMAP_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM)
90 #define IQS5XX_BL_ATTEMPTS 3
140 .addr = client->addr, in iqs5xx_read_burst()
146 .addr = client->addr, in iqs5xx_read_burst()
159 ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); in iqs5xx_read_burst()
167 ret = -EIO; in iqs5xx_read_burst()
169 dev_err(&client->dev, "Failed to read from address 0x%04X: %d\n", in iqs5xx_read_burst()
197 return -EINVAL; in iqs5xx_write_burst()
216 ret = -EIO; in iqs5xx_write_burst()
218 dev_err(&client->dev, "Failed to write to address 0x%04X: %d\n", in iqs5xx_write_burst()
240 gpiod_set_value_cansleep(iqs5xx->reset_gpio, 1); in iqs5xx_reset()
243 gpiod_set_value_cansleep(iqs5xx->reset_gpio, 0); in iqs5xx_reset()
252 msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK; in iqs5xx_bl_cmd()
269 return -EINVAL; in iqs5xx_bl_cmd()
272 ret = i2c_transfer(client->adapter, &msg, 1); in iqs5xx_bl_cmd()
284 * tolerate a relatively long clock-stretching period while the in iqs5xx_bl_cmd()
298 ret = i2c_transfer(client->adapter, &msg, 1); in iqs5xx_bl_cmd()
304 dev_err(&client->dev, "Unrecognized bootloader ID: 0x%04X\n", in iqs5xx_bl_cmd()
306 return -EINVAL; in iqs5xx_bl_cmd()
310 dev_err(&client->dev, "Bootloader CRC failed\n"); in iqs5xx_bl_cmd()
311 return -EIO; in iqs5xx_bl_cmd()
318 ret = -EIO; in iqs5xx_bl_cmd()
321 dev_err(&client->dev, in iqs5xx_bl_cmd()
322 "Unsuccessful bootloader command 0x%02X: %d\n", in iqs5xx_bl_cmd()
345 else if (error != -EINVAL) in iqs5xx_bl_open()
352 dev_err(&client->dev, "Failed to open bootloader: %d\n", error); in iqs5xx_bl_open()
365 return -EINVAL; in iqs5xx_bl_write()
367 msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK; in iqs5xx_bl_write()
375 sizeof(mbuf) - sizeof(bl_addr)); in iqs5xx_bl_write()
377 ret = i2c_transfer(client->adapter, &msg, 1); in iqs5xx_bl_write()
388 ret = -EIO; in iqs5xx_bl_write()
390 dev_err(&client->dev, "Failed to write block at address 0x%04X: %d\n", in iqs5xx_bl_write()
404 return -EINVAL; in iqs5xx_bl_verify()
406 msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK; in iqs5xx_bl_verify()
416 ret = i2c_transfer(client->adapter, &msg, 1); in iqs5xx_bl_verify()
421 dev_err(&client->dev, in iqs5xx_bl_verify()
422 "Failed to verify block at address 0x%04X\n", in iqs5xx_bl_verify()
424 return -EIO; in iqs5xx_bl_verify()
432 ret = -EIO; in iqs5xx_bl_verify()
434 dev_err(&client->dev, "Failed to read block at address 0x%04X: %d\n", in iqs5xx_bl_verify()
445 if (!iqs5xx->dev_id_info.bl_status) in iqs5xx_set_state()
448 mutex_lock(&iqs5xx->lock); in iqs5xx_set_state()
455 disable_irq(client->irq); in iqs5xx_set_state()
461 enable_irq(client->irq); in iqs5xx_set_state()
463 mutex_unlock(&iqs5xx->lock); in iqs5xx_set_state()
475 return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME); in iqs5xx_open()
482 iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND); in iqs5xx_close()
488 struct touchscreen_properties *prop = &iqs5xx->prop; in iqs5xx_axis_init()
489 struct input_dev *input = iqs5xx->input; in iqs5xx_axis_init()
494 input = devm_input_allocate_device(&client->dev); in iqs5xx_axis_init()
496 return -ENOMEM; in iqs5xx_axis_init()
498 input->name = client->name; in iqs5xx_axis_init()
499 input->id.bustype = BUS_I2C; in iqs5xx_axis_init()
500 input->open = iqs5xx_open; in iqs5xx_axis_init()
501 input->close = iqs5xx_close; in iqs5xx_axis_init()
504 iqs5xx->input = input; in iqs5xx_axis_init()
525 if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { in iqs5xx_axis_init()
526 dev_err(&client->dev, "Invalid touchscreen size: %u*%u\n", in iqs5xx_axis_init()
527 prop->max_x, prop->max_y); in iqs5xx_axis_init()
528 return -EINVAL; in iqs5xx_axis_init()
531 if (prop->max_x != max_x) { in iqs5xx_axis_init()
532 error = iqs5xx_write_word(client, IQS5XX_X_RES, prop->max_x); in iqs5xx_axis_init()
537 if (prop->max_y != max_y) { in iqs5xx_axis_init()
538 error = iqs5xx_write_word(client, IQS5XX_Y_RES, prop->max_y); in iqs5xx_axis_init()
546 dev_err(&client->dev, "Failed to initialize slots: %d\n", in iqs5xx_axis_init()
565 * A000 and B000 devices use 8-bit and 16-bit addressing, respectively. in iqs5xx_dev_init()
566 * Querying an A000 device's version information with 16-bit addressing in iqs5xx_dev_init()
574 switch (be16_to_cpu(dev_id_info->prod_num)) { in iqs5xx_dev_init()
580 dev_err(&client->dev, "Unrecognized product number: %u\n", in iqs5xx_dev_init()
581 be16_to_cpu(dev_id_info->prod_num)); in iqs5xx_dev_init()
582 return -EINVAL; in iqs5xx_dev_init()
591 dev_err(&client->dev, "Opening bootloader for A000 device\n"); in iqs5xx_dev_init()
596 iqs5xx->exp_file, sizeof(iqs5xx->exp_file)); in iqs5xx_dev_init()
623 iqs5xx->dev_id_info = *dev_id_info; in iqs5xx_dev_init()
640 struct i2c_client *client = iqs5xx->client; in iqs5xx_irq()
641 struct input_dev *input = iqs5xx->input; in iqs5xx_irq()
649 if (!iqs5xx->dev_id_info.bl_status) in iqs5xx_irq()
658 dev_err(&client->dev, "Unexpected device reset\n"); in iqs5xx_irq()
662 dev_err(&client->dev, in iqs5xx_irq()
663 "Failed to re-initialize device: %d\n", error); in iqs5xx_irq()
672 u16 pressure = be16_to_cpu(touch_data->strength); in iqs5xx_irq()
677 touchscreen_report_pos(input, &iqs5xx->prop, in iqs5xx_irq()
678 be16_to_cpu(touch_data->abs_x), in iqs5xx_irq()
679 be16_to_cpu(touch_data->abs_y), in iqs5xx_irq()
718 * to user-exported settings is not recalculated, and (2) an address of in iqs5xx_fw_file_parse()
724 error = request_firmware(&fw, fw_file, &client->dev); in iqs5xx_fw_file_parse()
726 dev_err(&client->dev, "Failed to request firmware %s: %d\n", in iqs5xx_fw_file_parse()
732 if (pos + sizeof(*rec) > fw->size) { in iqs5xx_fw_file_parse()
733 dev_err(&client->dev, "Insufficient firmware size\n"); in iqs5xx_fw_file_parse()
734 error = -EINVAL; in iqs5xx_fw_file_parse()
737 rec = (struct iqs5xx_ihex_rec *)(fw->data + pos); in iqs5xx_fw_file_parse()
740 if (rec->start != ':') { in iqs5xx_fw_file_parse()
741 dev_err(&client->dev, "Invalid start at record %u\n", in iqs5xx_fw_file_parse()
743 error = -EINVAL; in iqs5xx_fw_file_parse()
747 error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr)); in iqs5xx_fw_file_parse()
749 dev_err(&client->dev, "Invalid header at record %u\n", in iqs5xx_fw_file_parse()
758 if (pos + rec_len * 2 > fw->size) { in iqs5xx_fw_file_parse()
759 dev_err(&client->dev, "Insufficient firmware size\n"); in iqs5xx_fw_file_parse()
760 error = -EINVAL; in iqs5xx_fw_file_parse()
765 error = hex2bin(rec_data, rec->data, rec_len); in iqs5xx_fw_file_parse()
767 dev_err(&client->dev, "Invalid data at record %u\n", in iqs5xx_fw_file_parse()
773 rec->data + rec_len * 2, sizeof(rec_chksm)); in iqs5xx_fw_file_parse()
775 dev_err(&client->dev, "Invalid checksum at record %u\n", in iqs5xx_fw_file_parse()
788 dev_err(&client->dev, in iqs5xx_fw_file_parse()
791 error = -EINVAL; in iqs5xx_fw_file_parse()
799 dev_err(&client->dev, in iqs5xx_fw_file_parse()
802 error = -EINVAL; in iqs5xx_fw_file_parse()
804 memcpy(pmap + rec_addr - IQS5XX_CHKSM, in iqs5xx_fw_file_parse()
811 dev_err(&client->dev, "Invalid type at record %u\n", in iqs5xx_fw_file_parse()
813 error = -EINVAL; in iqs5xx_fw_file_parse()
820 while (pos < fw->size) { in iqs5xx_fw_file_parse()
821 if (*(fw->data + pos) == ':') in iqs5xx_fw_file_parse()
840 return -ENOMEM; in iqs5xx_fw_file_write()
846 mutex_lock(&iqs5xx->lock); in iqs5xx_fw_file_write()
853 disable_irq(client->irq); in iqs5xx_fw_file_write()
855 iqs5xx->dev_id_info.bl_status = 0; in iqs5xx_fw_file_write()
881 if (!iqs5xx->dev_id_info.bl_status) in iqs5xx_fw_file_write()
882 error_init = error_init ? : -EINVAL; in iqs5xx_fw_file_write()
884 enable_irq(client->irq); in iqs5xx_fw_file_write()
886 mutex_unlock(&iqs5xx->lock); in iqs5xx_fw_file_write()
899 struct i2c_client *client = iqs5xx->client; in fw_file_store()
901 bool input_reg = !iqs5xx->input; in fw_file_store()
906 return -EINVAL; in fw_file_store()
908 if (buf[len - 1] == '\n') in fw_file_store()
909 len--; in fw_file_store()
912 return -ENAMETOOLONG; in fw_file_store()
926 error = input_register_device(iqs5xx->input); in fw_file_store()
928 dev_err(&client->dev, in fw_file_store()
943 if (!iqs5xx->dev_id_info.bl_status) in fw_info_show()
944 return -ENODATA; in fw_info_show()
947 be16_to_cpu(iqs5xx->dev_id_info.prod_num), in fw_info_show()
948 be16_to_cpu(iqs5xx->dev_id_info.proj_num), in fw_info_show()
949 iqs5xx->dev_id_info.major_ver, in fw_info_show()
950 iqs5xx->dev_id_info.minor_ver, in fw_info_show()
951 iqs5xx->exp_file[0], iqs5xx->exp_file[1]); in fw_info_show()
970 (iqs5xx->dev_id_info.bl_status == IQS5XX_BL_STATUS_NONE || in iqs5xx_attr_is_visible()
971 !iqs5xx->reset_gpio)) in iqs5xx_attr_is_visible()
974 return attr->mode; in iqs5xx_attr_is_visible()
986 struct input_dev *input = iqs5xx->input; in iqs5xx_suspend()
992 mutex_lock(&input->mutex); in iqs5xx_suspend()
995 error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND); in iqs5xx_suspend()
997 mutex_unlock(&input->mutex); in iqs5xx_suspend()
1005 struct input_dev *input = iqs5xx->input; in iqs5xx_resume()
1011 mutex_lock(&input->mutex); in iqs5xx_resume()
1014 error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME); in iqs5xx_resume()
1016 mutex_unlock(&input->mutex); in iqs5xx_resume()
1028 iqs5xx = devm_kzalloc(&client->dev, sizeof(*iqs5xx), GFP_KERNEL); in iqs5xx_probe()
1030 return -ENOMEM; in iqs5xx_probe()
1033 iqs5xx->client = client; in iqs5xx_probe()
1035 iqs5xx->reset_gpio = devm_gpiod_get_optional(&client->dev, in iqs5xx_probe()
1037 if (IS_ERR(iqs5xx->reset_gpio)) { in iqs5xx_probe()
1038 error = PTR_ERR(iqs5xx->reset_gpio); in iqs5xx_probe()
1039 dev_err(&client->dev, "Failed to request GPIO: %d\n", error); in iqs5xx_probe()
1043 mutex_init(&iqs5xx->lock); in iqs5xx_probe()
1049 error = devm_request_threaded_irq(&client->dev, client->irq, in iqs5xx_probe()
1051 client->name, iqs5xx); in iqs5xx_probe()
1053 dev_err(&client->dev, "Failed to request IRQ: %d\n", error); in iqs5xx_probe()
1057 if (iqs5xx->input) { in iqs5xx_probe()
1058 error = input_register_device(iqs5xx->input); in iqs5xx_probe()
1060 dev_err(&client->dev, in iqs5xx_probe()
1097 MODULE_DESCRIPTION("Azoteq IQS550/572/525 Trackpad/Touchscreen Controller");