intel_cht_int33fe.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * Intel Cherry Trail ACPI INT33FE pseudo device driver
  3. *
  4. * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
  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 version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Some Intel Cherry Trail based device which ship with Windows 10, have
  11. * this weird INT33FE ACPI device with a CRS table with 4 I2cSerialBusV2
  12. * resources, for 4 different chips attached to various i2c busses:
  13. * 1. The Whiskey Cove pmic, which is also described by the INT34D3 ACPI device
  14. * 2. Maxim MAX17047 Fuel Gauge Controller
  15. * 3. FUSB302 USB Type-C Controller
  16. * 4. PI3USB30532 USB switch
  17. *
  18. * So this driver is a stub / pseudo driver whose only purpose is to
  19. * instantiate i2c-clients for chips 2 - 4, so that standard i2c drivers
  20. * for these chips can bind to the them.
  21. */
  22. #include <linux/acpi.h>
  23. #include <linux/i2c.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/module.h>
  26. #include <linux/slab.h>
  27. #define EXPECTED_PTYPE 4
  28. struct cht_int33fe_data {
  29. struct i2c_client *max17047;
  30. struct i2c_client *fusb302;
  31. struct i2c_client *pi3usb30532;
  32. };
  33. static const char * const max17047_suppliers[] = { "bq24190-charger" };
  34. static const struct property_entry max17047_props[] = {
  35. PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers),
  36. { }
  37. };
  38. static int cht_int33fe_probe(struct i2c_client *client)
  39. {
  40. struct device *dev = &client->dev;
  41. struct i2c_board_info board_info;
  42. struct cht_int33fe_data *data;
  43. unsigned long long ptyp;
  44. acpi_status status;
  45. int fusb302_irq;
  46. status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
  47. if (ACPI_FAILURE(status)) {
  48. dev_err(dev, "Error getting PTYPE\n");
  49. return -ENODEV;
  50. }
  51. /*
  52. * The same ACPI HID is used for different configurations check PTYP
  53. * to ensure that we are dealing with the expected config.
  54. */
  55. if (ptyp != EXPECTED_PTYPE)
  56. return -ENODEV;
  57. /* The FUSB302 uses the irq at index 1 and is the only irq user */
  58. fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1);
  59. if (fusb302_irq < 0) {
  60. if (fusb302_irq != -EPROBE_DEFER)
  61. dev_err(dev, "Error getting FUSB302 irq\n");
  62. return fusb302_irq;
  63. }
  64. data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  65. if (!data)
  66. return -ENOMEM;
  67. memset(&board_info, 0, sizeof(board_info));
  68. strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
  69. board_info.properties = max17047_props;
  70. data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
  71. if (!data->max17047)
  72. return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
  73. memset(&board_info, 0, sizeof(board_info));
  74. strlcpy(board_info.type, "fusb302", I2C_NAME_SIZE);
  75. board_info.irq = fusb302_irq;
  76. data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
  77. if (!data->fusb302)
  78. goto out_unregister_max17047;
  79. memset(&board_info, 0, sizeof(board_info));
  80. strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
  81. data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
  82. if (!data->pi3usb30532)
  83. goto out_unregister_fusb302;
  84. i2c_set_clientdata(client, data);
  85. return 0;
  86. out_unregister_fusb302:
  87. i2c_unregister_device(data->fusb302);
  88. out_unregister_max17047:
  89. i2c_unregister_device(data->max17047);
  90. return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
  91. }
  92. static int cht_int33fe_remove(struct i2c_client *i2c)
  93. {
  94. struct cht_int33fe_data *data = i2c_get_clientdata(i2c);
  95. i2c_unregister_device(data->pi3usb30532);
  96. i2c_unregister_device(data->fusb302);
  97. i2c_unregister_device(data->max17047);
  98. return 0;
  99. }
  100. static const struct i2c_device_id cht_int33fe_i2c_id[] = {
  101. { }
  102. };
  103. MODULE_DEVICE_TABLE(i2c, cht_int33fe_i2c_id);
  104. static const struct acpi_device_id cht_int33fe_acpi_ids[] = {
  105. { "INT33FE", },
  106. { }
  107. };
  108. MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids);
  109. static struct i2c_driver cht_int33fe_driver = {
  110. .driver = {
  111. .name = "Intel Cherry Trail ACPI INT33FE driver",
  112. .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids),
  113. },
  114. .probe_new = cht_int33fe_probe,
  115. .remove = cht_int33fe_remove,
  116. .id_table = cht_int33fe_i2c_id,
  117. .disable_i2c_core_irq_mapping = true,
  118. };
  119. module_i2c_driver(cht_int33fe_driver);
  120. MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver");
  121. MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
  122. MODULE_LICENSE("GPL");