fsl-imx25-tsadc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <[email protected]>
  4. */
  5. #include <linux/clk.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/irqchip/chained_irq.h>
  8. #include <linux/irqdesc.h>
  9. #include <linux/irqdomain.h>
  10. #include <linux/irq.h>
  11. #include <linux/mfd/imx25-tsadc.h>
  12. #include <linux/module.h>
  13. #include <linux/of.h>
  14. #include <linux/of_platform.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/regmap.h>
  17. static struct regmap_config mx25_tsadc_regmap_config = {
  18. .fast_io = true,
  19. .max_register = 8,
  20. .reg_bits = 32,
  21. .val_bits = 32,
  22. .reg_stride = 4,
  23. };
  24. static void mx25_tsadc_irq_handler(struct irq_desc *desc)
  25. {
  26. struct mx25_tsadc *tsadc = irq_desc_get_handler_data(desc);
  27. struct irq_chip *chip = irq_desc_get_chip(desc);
  28. u32 status;
  29. chained_irq_enter(chip, desc);
  30. regmap_read(tsadc->regs, MX25_TSC_TGSR, &status);
  31. if (status & MX25_TGSR_GCQ_INT)
  32. generic_handle_domain_irq(tsadc->domain, 1);
  33. if (status & MX25_TGSR_TCQ_INT)
  34. generic_handle_domain_irq(tsadc->domain, 0);
  35. chained_irq_exit(chip, desc);
  36. }
  37. static int mx25_tsadc_domain_map(struct irq_domain *d, unsigned int irq,
  38. irq_hw_number_t hwirq)
  39. {
  40. struct mx25_tsadc *tsadc = d->host_data;
  41. irq_set_chip_data(irq, tsadc);
  42. irq_set_chip_and_handler(irq, &dummy_irq_chip,
  43. handle_level_irq);
  44. irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE);
  45. return 0;
  46. }
  47. static const struct irq_domain_ops mx25_tsadc_domain_ops = {
  48. .map = mx25_tsadc_domain_map,
  49. .xlate = irq_domain_xlate_onecell,
  50. };
  51. static int mx25_tsadc_setup_irq(struct platform_device *pdev,
  52. struct mx25_tsadc *tsadc)
  53. {
  54. struct device *dev = &pdev->dev;
  55. struct device_node *np = dev->of_node;
  56. int irq;
  57. irq = platform_get_irq(pdev, 0);
  58. if (irq < 0)
  59. return irq;
  60. tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops,
  61. tsadc);
  62. if (!tsadc->domain) {
  63. dev_err(dev, "Failed to add irq domain\n");
  64. return -ENOMEM;
  65. }
  66. irq_set_chained_handler_and_data(irq, mx25_tsadc_irq_handler, tsadc);
  67. return 0;
  68. }
  69. static int mx25_tsadc_unset_irq(struct platform_device *pdev)
  70. {
  71. struct mx25_tsadc *tsadc = platform_get_drvdata(pdev);
  72. int irq = platform_get_irq(pdev, 0);
  73. if (irq >= 0) {
  74. irq_set_chained_handler_and_data(irq, NULL, NULL);
  75. irq_domain_remove(tsadc->domain);
  76. }
  77. return 0;
  78. }
  79. static void mx25_tsadc_setup_clk(struct platform_device *pdev,
  80. struct mx25_tsadc *tsadc)
  81. {
  82. unsigned clk_div;
  83. /*
  84. * According to the datasheet the ADC clock should never
  85. * exceed 1,75 MHz. Base clock is the IPG and the ADC unit uses
  86. * a funny clock divider. To keep the ADC conversion time constant
  87. * adapt the ADC internal clock divider to the IPG clock rate.
  88. */
  89. dev_dbg(&pdev->dev, "Found master clock at %lu Hz\n",
  90. clk_get_rate(tsadc->clk));
  91. clk_div = DIV_ROUND_UP(clk_get_rate(tsadc->clk), 1750000);
  92. dev_dbg(&pdev->dev, "Setting up ADC clock divider to %u\n", clk_div);
  93. /* adc clock = IPG clock / (2 * div + 2) */
  94. clk_div -= 2;
  95. clk_div /= 2;
  96. /*
  97. * the ADC clock divider changes its behaviour when values below 4
  98. * are used: it is fixed to "/ 10" in this case
  99. */
  100. clk_div = max_t(unsigned, 4, clk_div);
  101. dev_dbg(&pdev->dev, "Resulting ADC conversion clock at %lu Hz\n",
  102. clk_get_rate(tsadc->clk) / (2 * clk_div + 2));
  103. regmap_update_bits(tsadc->regs, MX25_TSC_TGCR,
  104. MX25_TGCR_ADCCLKCFG(0x1f),
  105. MX25_TGCR_ADCCLKCFG(clk_div));
  106. }
  107. static int mx25_tsadc_probe(struct platform_device *pdev)
  108. {
  109. struct device *dev = &pdev->dev;
  110. struct mx25_tsadc *tsadc;
  111. struct resource *res;
  112. int ret;
  113. void __iomem *iomem;
  114. tsadc = devm_kzalloc(dev, sizeof(*tsadc), GFP_KERNEL);
  115. if (!tsadc)
  116. return -ENOMEM;
  117. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  118. iomem = devm_ioremap_resource(dev, res);
  119. if (IS_ERR(iomem))
  120. return PTR_ERR(iomem);
  121. tsadc->regs = devm_regmap_init_mmio(dev, iomem,
  122. &mx25_tsadc_regmap_config);
  123. if (IS_ERR(tsadc->regs)) {
  124. dev_err(dev, "Failed to initialize regmap\n");
  125. return PTR_ERR(tsadc->regs);
  126. }
  127. tsadc->clk = devm_clk_get(dev, "ipg");
  128. if (IS_ERR(tsadc->clk)) {
  129. dev_err(dev, "Failed to get ipg clock\n");
  130. return PTR_ERR(tsadc->clk);
  131. }
  132. /* setup clock according to the datasheet */
  133. mx25_tsadc_setup_clk(pdev, tsadc);
  134. /* Enable clock and reset the component */
  135. regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_CLK_EN,
  136. MX25_TGCR_CLK_EN);
  137. regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_TSC_RST,
  138. MX25_TGCR_TSC_RST);
  139. /* Setup powersaving mode, but enable internal reference voltage */
  140. regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_POWERMODE_MASK,
  141. MX25_TGCR_POWERMODE_SAVE);
  142. regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_INTREFEN,
  143. MX25_TGCR_INTREFEN);
  144. ret = mx25_tsadc_setup_irq(pdev, tsadc);
  145. if (ret)
  146. return ret;
  147. platform_set_drvdata(pdev, tsadc);
  148. ret = devm_of_platform_populate(dev);
  149. if (ret)
  150. goto err_irq;
  151. return 0;
  152. err_irq:
  153. mx25_tsadc_unset_irq(pdev);
  154. return ret;
  155. }
  156. static int mx25_tsadc_remove(struct platform_device *pdev)
  157. {
  158. mx25_tsadc_unset_irq(pdev);
  159. return 0;
  160. }
  161. static const struct of_device_id mx25_tsadc_ids[] = {
  162. { .compatible = "fsl,imx25-tsadc" },
  163. { /* Sentinel */ }
  164. };
  165. MODULE_DEVICE_TABLE(of, mx25_tsadc_ids);
  166. static struct platform_driver mx25_tsadc_driver = {
  167. .driver = {
  168. .name = "mx25-tsadc",
  169. .of_match_table = mx25_tsadc_ids,
  170. },
  171. .probe = mx25_tsadc_probe,
  172. .remove = mx25_tsadc_remove,
  173. };
  174. module_platform_driver(mx25_tsadc_driver);
  175. MODULE_DESCRIPTION("MFD for ADC/TSC for Freescale mx25");
  176. MODULE_AUTHOR("Markus Pargmann <[email protected]>");
  177. MODULE_LICENSE("GPL v2");
  178. MODULE_ALIAS("platform:mx25-tsadc");