qpnp-revid.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/slab.h>
  14. #include <linux/spmi.h>
  15. #include <linux/err.h>
  16. #include <linux/qpnp-revid.h>
  17. #define REVID_REVISION1 0x0
  18. #define REVID_REVISION2 0x1
  19. #define REVID_REVISION3 0x2
  20. #define REVID_REVISION4 0x3
  21. #define REVID_TYPE 0x4
  22. #define REVID_SUBTYPE 0x5
  23. #define REVID_STATUS1 0x8
  24. #define QPNP_REVID_DEV_NAME "qcom,qpnp-revid"
  25. static const char *const pmic_names[] = {
  26. "Unknown PMIC",
  27. "PM8941",
  28. "PM8841",
  29. "PM8019",
  30. "PM8226",
  31. "PM8110",
  32. "PMA8084",
  33. "PMI8962",
  34. "PMD9635",
  35. };
  36. struct revid_chip {
  37. struct list_head link;
  38. struct device_node *dev_node;
  39. struct pmic_revid_data data;
  40. };
  41. static LIST_HEAD(revid_chips);
  42. static DEFINE_MUTEX(revid_chips_lock);
  43. static struct of_device_id qpnp_revid_match_table[] = {
  44. { .compatible = QPNP_REVID_DEV_NAME },
  45. {}
  46. };
  47. static u8 qpnp_read_byte(struct spmi_device *spmi, u16 addr)
  48. {
  49. int rc;
  50. u8 val;
  51. rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, &val, 1);
  52. if (rc) {
  53. pr_err("SPMI read failed rc=%d\n", rc);
  54. return 0;
  55. }
  56. return val;
  57. }
  58. /**
  59. * get_revid_data - Return the revision information of PMIC
  60. * @dev_node: Pointer to the revid peripheral of the PMIC for which
  61. * revision information is seeked
  62. *
  63. * CONTEXT: Should be called in non atomic context
  64. *
  65. * RETURNS: pointer to struct pmic_revid_data filled with the information
  66. * about the PMIC revision
  67. */
  68. struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
  69. {
  70. struct revid_chip *revid_chip;
  71. if (!dev_node)
  72. return ERR_PTR(-EINVAL);
  73. mutex_lock(&revid_chips_lock);
  74. list_for_each_entry(revid_chip, &revid_chips, link) {
  75. if (dev_node == revid_chip->dev_node) {
  76. mutex_unlock(&revid_chips_lock);
  77. return &revid_chip->data;
  78. }
  79. }
  80. mutex_unlock(&revid_chips_lock);
  81. return ERR_PTR(-EINVAL);
  82. }
  83. EXPORT_SYMBOL(get_revid_data);
  84. #define PM8941_PERIPHERAL_SUBTYPE 0x01
  85. #define PM8226_PERIPHERAL_SUBTYPE 0x04
  86. static size_t build_pmic_string(char *buf, size_t n, int sid,
  87. u8 subtype, u8 rev1, u8 rev2, u8 rev3, u8 rev4)
  88. {
  89. size_t pos = 0;
  90. /*
  91. * In early versions of PM8941 and PM8226, the major revision number
  92. * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
  93. * Increment the major revision number here if the chip is an early
  94. * version of PM8941 or PM8226.
  95. */
  96. if (((int)subtype == PM8941_PERIPHERAL_SUBTYPE
  97. || (int)subtype == PM8226_PERIPHERAL_SUBTYPE)
  98. && rev4 < 0x02)
  99. rev4++;
  100. pos += snprintf(buf + pos, n - pos, "PMIC@SID%d", sid);
  101. if (subtype >= ARRAY_SIZE(pmic_names) || subtype == 0)
  102. pos += snprintf(buf + pos, n - pos, ": %s (subtype: 0x%02X)",
  103. pmic_names[0], subtype);
  104. else
  105. pos += snprintf(buf + pos, n - pos, ": %s",
  106. pmic_names[subtype]);
  107. pos += snprintf(buf + pos, n - pos, " v%d.%d", rev4, rev3);
  108. if (rev2 || rev1)
  109. pos += snprintf(buf + pos, n - pos, ".%d", rev2);
  110. if (rev1)
  111. pos += snprintf(buf + pos, n - pos, ".%d", rev1);
  112. return pos;
  113. }
  114. #define PMIC_PERIPHERAL_TYPE 0x51
  115. #define PMIC_STRING_MAXLENGTH 80
  116. static int __devinit qpnp_revid_probe(struct spmi_device *spmi)
  117. {
  118. u8 rev1, rev2, rev3, rev4, pmic_type, pmic_subtype, pmic_status;
  119. u8 option1, option2, option3, option4;
  120. struct resource *resource;
  121. char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
  122. struct revid_chip *revid_chip;
  123. resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
  124. if (!resource) {
  125. pr_err("Unable to get spmi resource for REVID\n");
  126. return -EINVAL;
  127. }
  128. pmic_type = qpnp_read_byte(spmi, resource->start + REVID_TYPE);
  129. if (pmic_type != PMIC_PERIPHERAL_TYPE) {
  130. pr_err("Invalid REVID peripheral type: %02X\n", pmic_type);
  131. return -EINVAL;
  132. }
  133. rev1 = qpnp_read_byte(spmi, resource->start + REVID_REVISION1);
  134. rev2 = qpnp_read_byte(spmi, resource->start + REVID_REVISION2);
  135. rev3 = qpnp_read_byte(spmi, resource->start + REVID_REVISION3);
  136. rev4 = qpnp_read_byte(spmi, resource->start + REVID_REVISION4);
  137. pmic_subtype = qpnp_read_byte(spmi, resource->start + REVID_SUBTYPE);
  138. pmic_status = qpnp_read_byte(spmi, resource->start + REVID_STATUS1);
  139. revid_chip = devm_kzalloc(&spmi->dev, sizeof(struct revid_chip),
  140. GFP_KERNEL);
  141. if (!revid_chip)
  142. return -ENOMEM;
  143. revid_chip->dev_node = spmi->dev.of_node;
  144. revid_chip->data.rev1 = rev1;
  145. revid_chip->data.rev2 = rev2;
  146. revid_chip->data.rev3 = rev3;
  147. revid_chip->data.rev4 = rev4;
  148. revid_chip->data.pmic_subtype = pmic_subtype;
  149. revid_chip->data.pmic_type = pmic_type;
  150. mutex_lock(&revid_chips_lock);
  151. list_add(&revid_chip->link, &revid_chips);
  152. mutex_unlock(&revid_chips_lock);
  153. option1 = pmic_status & 0x3;
  154. option2 = (pmic_status >> 2) & 0x3;
  155. option3 = (pmic_status >> 4) & 0x3;
  156. option4 = (pmic_status >> 6) & 0x3;
  157. build_pmic_string(pmic_string, PMIC_STRING_MAXLENGTH, spmi->sid,
  158. pmic_subtype, rev1, rev2, rev3, rev4);
  159. pr_info("%s options: %d, %d, %d, %d\n",
  160. pmic_string, option1, option2, option3, option4);
  161. return 0;
  162. }
  163. static struct spmi_driver qpnp_revid_driver = {
  164. .probe = qpnp_revid_probe,
  165. .driver = {
  166. .name = QPNP_REVID_DEV_NAME,
  167. .owner = THIS_MODULE,
  168. .of_match_table = qpnp_revid_match_table,
  169. },
  170. };
  171. static int __init qpnp_revid_init(void)
  172. {
  173. return spmi_driver_register(&qpnp_revid_driver);
  174. }
  175. static void __exit qpnp_revid_exit(void)
  176. {
  177. return spmi_driver_unregister(&qpnp_revid_driver);
  178. }
  179. module_init(qpnp_revid_init);
  180. module_exit(qpnp_revid_exit);
  181. MODULE_DESCRIPTION("QPNP REVID DRIVER");
  182. MODULE_LICENSE("GPL v2");
  183. MODULE_ALIAS("platform:" QPNP_REVID_DEV_NAME);