silead_dmi.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Silead touchscreen driver DMI based configuration code
  3. *
  4. * Copyright (c) 2017 Red Hat Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Red Hat authors:
  12. * Hans de Goede <hdegoede@redhat.com>
  13. */
  14. #include <linux/acpi.h>
  15. #include <linux/device.h>
  16. #include <linux/dmi.h>
  17. #include <linux/i2c.h>
  18. #include <linux/notifier.h>
  19. #include <linux/property.h>
  20. #include <linux/string.h>
  21. struct silead_ts_dmi_data {
  22. const char *acpi_name;
  23. struct property_entry *properties;
  24. };
  25. static struct property_entry cube_iwork8_air_props[] = {
  26. PROPERTY_ENTRY_U32("touchscreen-size-x", 1660),
  27. PROPERTY_ENTRY_U32("touchscreen-size-y", 900),
  28. PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
  29. PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"),
  30. PROPERTY_ENTRY_U32("silead,max-fingers", 10),
  31. { }
  32. };
  33. static const struct silead_ts_dmi_data cube_iwork8_air_data = {
  34. .acpi_name = "MSSL1680:00",
  35. .properties = cube_iwork8_air_props,
  36. };
  37. static struct property_entry jumper_ezpad_mini3_props[] = {
  38. PROPERTY_ENTRY_U32("touchscreen-size-x", 1700),
  39. PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
  40. PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
  41. PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"),
  42. PROPERTY_ENTRY_U32("silead,max-fingers", 10),
  43. { }
  44. };
  45. static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = {
  46. .acpi_name = "MSSL1680:00",
  47. .properties = jumper_ezpad_mini3_props,
  48. };
  49. static const struct dmi_system_id silead_ts_dmi_table[] = {
  50. {
  51. /* CUBE iwork8 Air */
  52. .driver_data = (void *)&cube_iwork8_air_data,
  53. .matches = {
  54. DMI_MATCH(DMI_SYS_VENDOR, "cube"),
  55. DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"),
  56. DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
  57. },
  58. },
  59. {
  60. /* Jumper EZpad mini3 */
  61. .driver_data = (void *)&jumper_ezpad_mini3_data,
  62. .matches = {
  63. DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
  64. /* jumperx.T87.KFBNEEA02 with the version-nr dropped */
  65. DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
  66. },
  67. },
  68. { },
  69. };
  70. static void silead_ts_dmi_add_props(struct device *dev)
  71. {
  72. struct i2c_client *client = to_i2c_client(dev);
  73. const struct dmi_system_id *dmi_id;
  74. const struct silead_ts_dmi_data *ts_data;
  75. int error;
  76. dmi_id = dmi_first_match(silead_ts_dmi_table);
  77. if (!dmi_id)
  78. return;
  79. ts_data = dmi_id->driver_data;
  80. if (has_acpi_companion(dev) &&
  81. !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) {
  82. error = device_add_properties(dev, ts_data->properties);
  83. if (error)
  84. dev_err(dev, "failed to add properties: %d\n", error);
  85. }
  86. }
  87. static int silead_ts_dmi_notifier_call(struct notifier_block *nb,
  88. unsigned long action, void *data)
  89. {
  90. struct device *dev = data;
  91. switch (action) {
  92. case BUS_NOTIFY_ADD_DEVICE:
  93. silead_ts_dmi_add_props(dev);
  94. break;
  95. default:
  96. break;
  97. }
  98. return 0;
  99. }
  100. static struct notifier_block silead_ts_dmi_notifier = {
  101. .notifier_call = silead_ts_dmi_notifier_call,
  102. };
  103. static int __init silead_ts_dmi_init(void)
  104. {
  105. int error;
  106. error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier);
  107. if (error)
  108. pr_err("%s: failed to register i2c bus notifier: %d\n",
  109. __func__, error);
  110. return error;
  111. }
  112. /*
  113. * We are registering out notifier after i2c core is initialized and i2c bus
  114. * itself is ready (which happens at postcore initcall level), but before
  115. * ACPI starts enumerating devices (at subsys initcall level).
  116. */
  117. arch_initcall(silead_ts_dmi_init);