da9063-core.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Device access for Dialog DA9063 modules
  4. *
  5. * Copyright 2012 Dialog Semiconductors Ltd.
  6. * Copyright 2013 Philipp Zabel, Pengutronix
  7. *
  8. * Author: Krystian Garbaciak, Dialog Semiconductor
  9. * Author: Michal Hajduk, Dialog Semiconductor
  10. *
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/init.h>
  15. #include <linux/slab.h>
  16. #include <linux/device.h>
  17. #include <linux/delay.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/mutex.h>
  20. #include <linux/mfd/core.h>
  21. #include <linux/regmap.h>
  22. #include <linux/mfd/da9063/core.h>
  23. #include <linux/mfd/da9063/registers.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/kthread.h>
  26. #include <linux/uaccess.h>
  27. static const struct resource da9063_regulators_resources[] = {
  28. {
  29. .name = "LDO_LIM",
  30. .start = DA9063_IRQ_LDO_LIM,
  31. .end = DA9063_IRQ_LDO_LIM,
  32. .flags = IORESOURCE_IRQ,
  33. },
  34. };
  35. static const struct resource da9063_rtc_resources[] = {
  36. {
  37. .name = "ALARM",
  38. .start = DA9063_IRQ_ALARM,
  39. .end = DA9063_IRQ_ALARM,
  40. .flags = IORESOURCE_IRQ,
  41. },
  42. {
  43. .name = "TICK",
  44. .start = DA9063_IRQ_TICK,
  45. .end = DA9063_IRQ_TICK,
  46. .flags = IORESOURCE_IRQ,
  47. }
  48. };
  49. static const struct resource da9063_onkey_resources[] = {
  50. {
  51. .name = "ONKEY",
  52. .start = DA9063_IRQ_ONKEY,
  53. .end = DA9063_IRQ_ONKEY,
  54. .flags = IORESOURCE_IRQ,
  55. },
  56. };
  57. static const struct resource da9063_hwmon_resources[] = {
  58. {
  59. .start = DA9063_IRQ_ADC_RDY,
  60. .end = DA9063_IRQ_ADC_RDY,
  61. .flags = IORESOURCE_IRQ,
  62. },
  63. };
  64. static const struct mfd_cell da9063_common_devs[] = {
  65. {
  66. .name = DA9063_DRVNAME_REGULATORS,
  67. .num_resources = ARRAY_SIZE(da9063_regulators_resources),
  68. .resources = da9063_regulators_resources,
  69. },
  70. {
  71. .name = DA9063_DRVNAME_LEDS,
  72. },
  73. {
  74. .name = DA9063_DRVNAME_WATCHDOG,
  75. .of_compatible = "dlg,da9063-watchdog",
  76. },
  77. {
  78. .name = DA9063_DRVNAME_HWMON,
  79. .num_resources = ARRAY_SIZE(da9063_hwmon_resources),
  80. .resources = da9063_hwmon_resources,
  81. },
  82. {
  83. .name = DA9063_DRVNAME_ONKEY,
  84. .num_resources = ARRAY_SIZE(da9063_onkey_resources),
  85. .resources = da9063_onkey_resources,
  86. .of_compatible = "dlg,da9063-onkey",
  87. },
  88. {
  89. .name = DA9063_DRVNAME_VIBRATION,
  90. },
  91. };
  92. /* Only present on DA9063 , not on DA9063L */
  93. static const struct mfd_cell da9063_devs[] = {
  94. {
  95. .name = DA9063_DRVNAME_RTC,
  96. .num_resources = ARRAY_SIZE(da9063_rtc_resources),
  97. .resources = da9063_rtc_resources,
  98. .of_compatible = "dlg,da9063-rtc",
  99. },
  100. };
  101. static int da9063_clear_fault_log(struct da9063 *da9063)
  102. {
  103. int ret = 0;
  104. int fault_log = 0;
  105. ret = regmap_read(da9063->regmap, DA9063_REG_FAULT_LOG, &fault_log);
  106. if (ret < 0) {
  107. dev_err(da9063->dev, "Cannot read FAULT_LOG.\n");
  108. return -EIO;
  109. }
  110. if (fault_log) {
  111. if (fault_log & DA9063_TWD_ERROR)
  112. dev_dbg(da9063->dev,
  113. "Fault log entry detected: DA9063_TWD_ERROR\n");
  114. if (fault_log & DA9063_POR)
  115. dev_dbg(da9063->dev,
  116. "Fault log entry detected: DA9063_POR\n");
  117. if (fault_log & DA9063_VDD_FAULT)
  118. dev_dbg(da9063->dev,
  119. "Fault log entry detected: DA9063_VDD_FAULT\n");
  120. if (fault_log & DA9063_VDD_START)
  121. dev_dbg(da9063->dev,
  122. "Fault log entry detected: DA9063_VDD_START\n");
  123. if (fault_log & DA9063_TEMP_CRIT)
  124. dev_dbg(da9063->dev,
  125. "Fault log entry detected: DA9063_TEMP_CRIT\n");
  126. if (fault_log & DA9063_KEY_RESET)
  127. dev_dbg(da9063->dev,
  128. "Fault log entry detected: DA9063_KEY_RESET\n");
  129. if (fault_log & DA9063_NSHUTDOWN)
  130. dev_dbg(da9063->dev,
  131. "Fault log entry detected: DA9063_NSHUTDOWN\n");
  132. if (fault_log & DA9063_WAIT_SHUT)
  133. dev_dbg(da9063->dev,
  134. "Fault log entry detected: DA9063_WAIT_SHUT\n");
  135. }
  136. ret = regmap_write(da9063->regmap,
  137. DA9063_REG_FAULT_LOG,
  138. fault_log);
  139. if (ret < 0)
  140. dev_err(da9063->dev,
  141. "Cannot reset FAULT_LOG values %d\n", ret);
  142. return ret;
  143. }
  144. int da9063_device_init(struct da9063 *da9063, unsigned int irq)
  145. {
  146. int ret;
  147. ret = da9063_clear_fault_log(da9063);
  148. if (ret < 0)
  149. dev_err(da9063->dev, "Cannot clear fault log\n");
  150. da9063->flags = 0;
  151. da9063->irq_base = -1;
  152. da9063->chip_irq = irq;
  153. ret = da9063_irq_init(da9063);
  154. if (ret) {
  155. dev_err(da9063->dev, "Cannot initialize interrupts.\n");
  156. return ret;
  157. }
  158. da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
  159. ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE,
  160. da9063_common_devs,
  161. ARRAY_SIZE(da9063_common_devs),
  162. NULL, da9063->irq_base, NULL);
  163. if (ret) {
  164. dev_err(da9063->dev, "Failed to add child devices\n");
  165. return ret;
  166. }
  167. if (da9063->type == PMIC_TYPE_DA9063) {
  168. ret = devm_mfd_add_devices(da9063->dev, PLATFORM_DEVID_NONE,
  169. da9063_devs, ARRAY_SIZE(da9063_devs),
  170. NULL, da9063->irq_base, NULL);
  171. if (ret) {
  172. dev_err(da9063->dev, "Failed to add child devices\n");
  173. return ret;
  174. }
  175. }
  176. return ret;
  177. }
  178. MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
  179. MODULE_AUTHOR("Krystian Garbaciak");
  180. MODULE_AUTHOR("Michal Hajduk");
  181. MODULE_LICENSE("GPL");