mt6397-core.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2014 MediaTek Inc.
  3. * Author: Flora Fu, MediaTek
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/interrupt.h>
  15. #include <linux/module.h>
  16. #include <linux/of_device.h>
  17. #include <linux/of_irq.h>
  18. #include <linux/regmap.h>
  19. #include <linux/mfd/core.h>
  20. #include <linux/mfd/mt6397/core.h>
  21. #include <linux/mfd/mt6397/registers.h>
  22. #define MT6397_RTC_BASE 0xe000
  23. #define MT6397_RTC_SIZE 0x3e
  24. static const struct resource mt6397_rtc_resources[] = {
  25. {
  26. .start = MT6397_RTC_BASE,
  27. .end = MT6397_RTC_BASE + MT6397_RTC_SIZE,
  28. .flags = IORESOURCE_MEM,
  29. },
  30. {
  31. .start = MT6397_IRQ_RTC,
  32. .end = MT6397_IRQ_RTC,
  33. .flags = IORESOURCE_IRQ,
  34. },
  35. };
  36. static const struct mfd_cell mt6397_devs[] = {
  37. {
  38. .name = "mt6397-rtc",
  39. .num_resources = ARRAY_SIZE(mt6397_rtc_resources),
  40. .resources = mt6397_rtc_resources,
  41. .of_compatible = "mediatek,mt6397-rtc",
  42. }, {
  43. .name = "mt6397-regulator",
  44. .of_compatible = "mediatek,mt6397-regulator",
  45. }, {
  46. .name = "mt6397-codec",
  47. .of_compatible = "mediatek,mt6397-codec",
  48. }, {
  49. .name = "mt6397-clk",
  50. .of_compatible = "mediatek,mt6397-clk",
  51. }, {
  52. .name = "mt6397-pinctrl",
  53. .of_compatible = "mediatek,mt6397-pinctrl",
  54. },
  55. };
  56. static void mt6397_irq_lock(struct irq_data *data)
  57. {
  58. struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
  59. mutex_lock(&mt6397->irqlock);
  60. }
  61. static void mt6397_irq_sync_unlock(struct irq_data *data)
  62. {
  63. struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
  64. regmap_write(mt6397->regmap, MT6397_INT_CON0, mt6397->irq_masks_cur[0]);
  65. regmap_write(mt6397->regmap, MT6397_INT_CON1, mt6397->irq_masks_cur[1]);
  66. mutex_unlock(&mt6397->irqlock);
  67. }
  68. static void mt6397_irq_disable(struct irq_data *data)
  69. {
  70. struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
  71. int shift = data->hwirq & 0xf;
  72. int reg = data->hwirq >> 4;
  73. mt6397->irq_masks_cur[reg] &= ~BIT(shift);
  74. }
  75. static void mt6397_irq_enable(struct irq_data *data)
  76. {
  77. struct mt6397_chip *mt6397 = irq_get_chip_data(data->irq);
  78. int shift = data->hwirq & 0xf;
  79. int reg = data->hwirq >> 4;
  80. mt6397->irq_masks_cur[reg] |= BIT(shift);
  81. }
  82. static struct irq_chip mt6397_irq_chip = {
  83. .name = "mt6397-irq",
  84. .irq_bus_lock = mt6397_irq_lock,
  85. .irq_bus_sync_unlock = mt6397_irq_sync_unlock,
  86. .irq_enable = mt6397_irq_enable,
  87. .irq_disable = mt6397_irq_disable,
  88. };
  89. static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
  90. int irqbase)
  91. {
  92. unsigned int status;
  93. int i, irq, ret;
  94. ret = regmap_read(mt6397->regmap, reg, &status);
  95. if (ret) {
  96. dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret);
  97. return;
  98. }
  99. for (i = 0; i < 16; i++) {
  100. if (status & BIT(i)) {
  101. irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);
  102. if (irq)
  103. handle_nested_irq(irq);
  104. }
  105. }
  106. regmap_write(mt6397->regmap, reg, status);
  107. }
  108. static irqreturn_t mt6397_irq_thread(int irq, void *data)
  109. {
  110. struct mt6397_chip *mt6397 = data;
  111. mt6397_irq_handle_reg(mt6397, MT6397_INT_STATUS0, 0);
  112. mt6397_irq_handle_reg(mt6397, MT6397_INT_STATUS1, 16);
  113. return IRQ_HANDLED;
  114. }
  115. static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq,
  116. irq_hw_number_t hw)
  117. {
  118. struct mt6397_chip *mt6397 = d->host_data;
  119. irq_set_chip_data(irq, mt6397);
  120. irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq);
  121. irq_set_nested_thread(irq, 1);
  122. #ifdef CONFIG_ARM
  123. set_irq_flags(irq, IRQF_VALID);
  124. #else
  125. irq_set_noprobe(irq);
  126. #endif
  127. return 0;
  128. }
  129. static const struct irq_domain_ops mt6397_irq_domain_ops = {
  130. .map = mt6397_irq_domain_map,
  131. };
  132. static int mt6397_irq_init(struct mt6397_chip *mt6397)
  133. {
  134. int ret;
  135. mutex_init(&mt6397->irqlock);
  136. /* Mask all interrupt sources */
  137. regmap_write(mt6397->regmap, MT6397_INT_CON0, 0x0);
  138. regmap_write(mt6397->regmap, MT6397_INT_CON1, 0x0);
  139. mt6397->irq_domain = irq_domain_add_linear(mt6397->dev->of_node,
  140. MT6397_IRQ_NR, &mt6397_irq_domain_ops, mt6397);
  141. if (!mt6397->irq_domain) {
  142. dev_err(mt6397->dev, "could not create irq domain\n");
  143. return -ENOMEM;
  144. }
  145. ret = devm_request_threaded_irq(mt6397->dev, mt6397->irq, NULL,
  146. mt6397_irq_thread, IRQF_ONESHOT, "mt6397-pmic", mt6397);
  147. if (ret) {
  148. dev_err(mt6397->dev, "failed to register irq=%d; err: %d\n",
  149. mt6397->irq, ret);
  150. return ret;
  151. }
  152. return 0;
  153. }
  154. static int mt6397_probe(struct platform_device *pdev)
  155. {
  156. int ret;
  157. struct mt6397_chip *mt6397;
  158. mt6397 = devm_kzalloc(&pdev->dev, sizeof(*mt6397), GFP_KERNEL);
  159. if (!mt6397)
  160. return -ENOMEM;
  161. mt6397->dev = &pdev->dev;
  162. /*
  163. * mt6397 MFD is child device of soc pmic wrapper.
  164. * Regmap is set from its parent.
  165. */
  166. mt6397->regmap = dev_get_regmap(pdev->dev.parent, NULL);
  167. if (!mt6397->regmap)
  168. return -ENODEV;
  169. platform_set_drvdata(pdev, mt6397);
  170. mt6397->irq = platform_get_irq(pdev, 0);
  171. if (mt6397->irq > 0) {
  172. ret = mt6397_irq_init(mt6397);
  173. if (ret)
  174. return ret;
  175. }
  176. ret = mfd_add_devices(&pdev->dev, -1, mt6397_devs,
  177. ARRAY_SIZE(mt6397_devs), NULL, 0, NULL);
  178. if (ret)
  179. dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
  180. return ret;
  181. }
  182. static int mt6397_remove(struct platform_device *pdev)
  183. {
  184. mfd_remove_devices(&pdev->dev);
  185. return 0;
  186. }
  187. static const struct of_device_id mt6397_of_match[] = {
  188. { .compatible = "mediatek,mt6397" },
  189. { }
  190. };
  191. MODULE_DEVICE_TABLE(of, mt6397_of_match);
  192. static struct platform_driver mt6397_driver = {
  193. .probe = mt6397_probe,
  194. .remove = mt6397_remove,
  195. .driver = {
  196. .name = "mt6397",
  197. .of_match_table = of_match_ptr(mt6397_of_match),
  198. },
  199. };
  200. module_platform_driver(mt6397_driver);
  201. MODULE_AUTHOR("Flora Fu, MediaTek");
  202. MODULE_DESCRIPTION("Driver for MediaTek MT6397 PMIC");
  203. MODULE_LICENSE("GPL");
  204. MODULE_ALIAS("platform:mt6397");