max77650.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright (C) 2018 BayLibre SAS
  4. // Author: Bartosz Golaszewski <[email protected]>
  5. //
  6. // Core MFD driver for MAXIM 77650/77651 charger/power-supply.
  7. // Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf
  8. #include <linux/i2c.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/irq.h>
  11. #include <linux/mfd/core.h>
  12. #include <linux/mfd/max77650.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/regmap.h>
  16. #define MAX77650_INT_GPI_F_MSK BIT(0)
  17. #define MAX77650_INT_GPI_R_MSK BIT(1)
  18. #define MAX77650_INT_GPI_MSK \
  19. (MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK)
  20. #define MAX77650_INT_nEN_F_MSK BIT(2)
  21. #define MAX77650_INT_nEN_R_MSK BIT(3)
  22. #define MAX77650_INT_TJAL1_R_MSK BIT(4)
  23. #define MAX77650_INT_TJAL2_R_MSK BIT(5)
  24. #define MAX77650_INT_DOD_R_MSK BIT(6)
  25. #define MAX77650_INT_THM_MSK BIT(0)
  26. #define MAX77650_INT_CHG_MSK BIT(1)
  27. #define MAX77650_INT_CHGIN_MSK BIT(2)
  28. #define MAX77650_INT_TJ_REG_MSK BIT(3)
  29. #define MAX77650_INT_CHGIN_CTRL_MSK BIT(4)
  30. #define MAX77650_INT_SYS_CTRL_MSK BIT(5)
  31. #define MAX77650_INT_SYS_CNFG_MSK BIT(6)
  32. #define MAX77650_INT_GLBL_OFFSET 0
  33. #define MAX77650_INT_CHG_OFFSET 1
  34. #define MAX77650_SBIA_LPM_MASK BIT(5)
  35. #define MAX77650_SBIA_LPM_DISABLED 0x00
  36. enum {
  37. MAX77650_INT_GPI,
  38. MAX77650_INT_nEN_F,
  39. MAX77650_INT_nEN_R,
  40. MAX77650_INT_TJAL1_R,
  41. MAX77650_INT_TJAL2_R,
  42. MAX77650_INT_DOD_R,
  43. MAX77650_INT_THM,
  44. MAX77650_INT_CHG,
  45. MAX77650_INT_CHGIN,
  46. MAX77650_INT_TJ_REG,
  47. MAX77650_INT_CHGIN_CTRL,
  48. MAX77650_INT_SYS_CTRL,
  49. MAX77650_INT_SYS_CNFG,
  50. };
  51. static const struct resource max77650_charger_resources[] = {
  52. DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"),
  53. DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"),
  54. };
  55. static const struct resource max77650_gpio_resources[] = {
  56. DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"),
  57. };
  58. static const struct resource max77650_onkey_resources[] = {
  59. DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"),
  60. DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"),
  61. };
  62. static const struct mfd_cell max77650_cells[] = {
  63. {
  64. .name = "max77650-regulator",
  65. .of_compatible = "maxim,max77650-regulator",
  66. }, {
  67. .name = "max77650-charger",
  68. .of_compatible = "maxim,max77650-charger",
  69. .resources = max77650_charger_resources,
  70. .num_resources = ARRAY_SIZE(max77650_charger_resources),
  71. }, {
  72. .name = "max77650-gpio",
  73. .of_compatible = "maxim,max77650-gpio",
  74. .resources = max77650_gpio_resources,
  75. .num_resources = ARRAY_SIZE(max77650_gpio_resources),
  76. }, {
  77. .name = "max77650-led",
  78. .of_compatible = "maxim,max77650-led",
  79. }, {
  80. .name = "max77650-onkey",
  81. .of_compatible = "maxim,max77650-onkey",
  82. .resources = max77650_onkey_resources,
  83. .num_resources = ARRAY_SIZE(max77650_onkey_resources),
  84. },
  85. };
  86. static const struct regmap_irq max77650_irqs[] = {
  87. [MAX77650_INT_GPI] = {
  88. .reg_offset = MAX77650_INT_GLBL_OFFSET,
  89. .mask = MAX77650_INT_GPI_MSK,
  90. .type = {
  91. .type_falling_val = MAX77650_INT_GPI_F_MSK,
  92. .type_rising_val = MAX77650_INT_GPI_R_MSK,
  93. .types_supported = IRQ_TYPE_EDGE_BOTH,
  94. },
  95. },
  96. REGMAP_IRQ_REG(MAX77650_INT_nEN_F,
  97. MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK),
  98. REGMAP_IRQ_REG(MAX77650_INT_nEN_R,
  99. MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK),
  100. REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R,
  101. MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK),
  102. REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R,
  103. MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK),
  104. REGMAP_IRQ_REG(MAX77650_INT_DOD_R,
  105. MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK),
  106. REGMAP_IRQ_REG(MAX77650_INT_THM,
  107. MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK),
  108. REGMAP_IRQ_REG(MAX77650_INT_CHG,
  109. MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK),
  110. REGMAP_IRQ_REG(MAX77650_INT_CHGIN,
  111. MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK),
  112. REGMAP_IRQ_REG(MAX77650_INT_TJ_REG,
  113. MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK),
  114. REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL,
  115. MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK),
  116. REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL,
  117. MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK),
  118. REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG,
  119. MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK),
  120. };
  121. static const struct regmap_irq_chip max77650_irq_chip = {
  122. .name = "max77650-irq",
  123. .irqs = max77650_irqs,
  124. .num_irqs = ARRAY_SIZE(max77650_irqs),
  125. .num_regs = 2,
  126. .status_base = MAX77650_REG_INT_GLBL,
  127. .mask_base = MAX77650_REG_INTM_GLBL,
  128. .type_in_mask = true,
  129. .type_invert = true,
  130. .init_ack_masked = true,
  131. .clear_on_unmask = true,
  132. };
  133. static const struct regmap_config max77650_regmap_config = {
  134. .name = "max77650",
  135. .reg_bits = 8,
  136. .val_bits = 8,
  137. };
  138. static int max77650_i2c_probe(struct i2c_client *i2c)
  139. {
  140. struct regmap_irq_chip_data *irq_data;
  141. struct device *dev = &i2c->dev;
  142. struct irq_domain *domain;
  143. struct regmap *map;
  144. unsigned int val;
  145. int rv, id;
  146. map = devm_regmap_init_i2c(i2c, &max77650_regmap_config);
  147. if (IS_ERR(map)) {
  148. dev_err(dev, "Unable to initialise I2C Regmap\n");
  149. return PTR_ERR(map);
  150. }
  151. rv = regmap_read(map, MAX77650_REG_CID, &val);
  152. if (rv) {
  153. dev_err(dev, "Unable to read Chip ID\n");
  154. return rv;
  155. }
  156. id = MAX77650_CID_BITS(val);
  157. switch (id) {
  158. case MAX77650_CID_77650A:
  159. case MAX77650_CID_77650C:
  160. case MAX77650_CID_77651A:
  161. case MAX77650_CID_77651B:
  162. break;
  163. default:
  164. dev_err(dev, "Chip not supported - ID: 0x%02x\n", id);
  165. return -ENODEV;
  166. }
  167. /*
  168. * This IC has a low-power mode which reduces the quiescent current
  169. * consumption to ~5.6uA but is only suitable for systems consuming
  170. * less than ~2mA. Since this is not likely the case even on
  171. * linux-based wearables - keep the chip in normal power mode.
  172. */
  173. rv = regmap_update_bits(map,
  174. MAX77650_REG_CNFG_GLBL,
  175. MAX77650_SBIA_LPM_MASK,
  176. MAX77650_SBIA_LPM_DISABLED);
  177. if (rv) {
  178. dev_err(dev, "Unable to change the power mode\n");
  179. return rv;
  180. }
  181. rv = devm_regmap_add_irq_chip(dev, map, i2c->irq,
  182. IRQF_ONESHOT | IRQF_SHARED, 0,
  183. &max77650_irq_chip, &irq_data);
  184. if (rv) {
  185. dev_err(dev, "Unable to add Regmap IRQ chip\n");
  186. return rv;
  187. }
  188. domain = regmap_irq_get_domain(irq_data);
  189. return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
  190. max77650_cells, ARRAY_SIZE(max77650_cells),
  191. NULL, 0, domain);
  192. }
  193. static const struct of_device_id max77650_of_match[] = {
  194. { .compatible = "maxim,max77650" },
  195. { }
  196. };
  197. MODULE_DEVICE_TABLE(of, max77650_of_match);
  198. static struct i2c_driver max77650_i2c_driver = {
  199. .driver = {
  200. .name = "max77650",
  201. .of_match_table = max77650_of_match,
  202. },
  203. .probe_new = max77650_i2c_probe,
  204. };
  205. module_i2c_driver(max77650_i2c_driver);
  206. MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver");
  207. MODULE_AUTHOR("Bartosz Golaszewski <[email protected]>");
  208. MODULE_LICENSE("GPL v2");