exynos-adc.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright (C) 2015 Samsung Electronics
  3. * Przemyslaw Marczak <p.marczak@samsung.com>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <errno.h>
  9. #include <dm.h>
  10. #include <adc.h>
  11. #include <asm/arch/adc.h>
  12. struct exynos_adc_priv {
  13. int active_channel;
  14. struct exynos_adc_v2 *regs;
  15. };
  16. int exynos_adc_channel_data(struct udevice *dev, int channel,
  17. unsigned int *data)
  18. {
  19. struct exynos_adc_priv *priv = dev_get_priv(dev);
  20. struct exynos_adc_v2 *regs = priv->regs;
  21. if (channel != priv->active_channel) {
  22. error("Requested channel is not active!");
  23. return -EINVAL;
  24. }
  25. if (ADC_V2_GET_STATUS_FLAG(readl(&regs->status)) != FLAG_CONV_END)
  26. return -EBUSY;
  27. *data = readl(&regs->dat) & ADC_V2_DAT_MASK;
  28. return 0;
  29. }
  30. int exynos_adc_start_channel(struct udevice *dev, int channel)
  31. {
  32. struct exynos_adc_priv *priv = dev_get_priv(dev);
  33. struct exynos_adc_v2 *regs = priv->regs;
  34. unsigned int cfg;
  35. /* Choose channel */
  36. cfg = readl(&regs->con2);
  37. cfg &= ~ADC_V2_CON2_CHAN_SEL_MASK;
  38. cfg |= ADC_V2_CON2_CHAN_SEL(channel);
  39. writel(cfg, &regs->con2);
  40. /* Start conversion */
  41. cfg = readl(&regs->con1);
  42. writel(cfg | ADC_V2_CON1_STC_EN, &regs->con1);
  43. priv->active_channel = channel;
  44. return 0;
  45. }
  46. int exynos_adc_stop(struct udevice *dev)
  47. {
  48. struct exynos_adc_priv *priv = dev_get_priv(dev);
  49. struct exynos_adc_v2 *regs = priv->regs;
  50. unsigned int cfg;
  51. /* Stop conversion */
  52. cfg = readl(&regs->con1);
  53. cfg |= ~ADC_V2_CON1_STC_EN;
  54. writel(cfg, &regs->con1);
  55. priv->active_channel = -1;
  56. return 0;
  57. }
  58. int exynos_adc_probe(struct udevice *dev)
  59. {
  60. struct exynos_adc_priv *priv = dev_get_priv(dev);
  61. struct exynos_adc_v2 *regs = priv->regs;
  62. unsigned int cfg;
  63. /* Check HW version */
  64. if (readl(&regs->version) != ADC_V2_VERSION) {
  65. error("This driver supports only ADC v2!");
  66. return -ENXIO;
  67. }
  68. /* ADC Reset */
  69. writel(ADC_V2_CON1_SOFT_RESET, &regs->con1);
  70. /* Disable INT - will read status only */
  71. writel(0x0, &regs->int_en);
  72. /* CON2 - set conversion parameters */
  73. cfg = ADC_V2_CON2_C_TIME(3); /* Conversion times: (1 << 3) = 8 */
  74. cfg |= ADC_V2_CON2_OSEL(OSEL_BINARY);
  75. cfg |= ADC_V2_CON2_ESEL(ESEL_ADC_EVAL_TIME_20CLK);
  76. cfg |= ADC_V2_CON2_HIGHF(HIGHF_CONV_RATE_600KSPS);
  77. writel(cfg, &regs->con2);
  78. priv->active_channel = -1;
  79. return 0;
  80. }
  81. int exynos_adc_ofdata_to_platdata(struct udevice *dev)
  82. {
  83. struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
  84. struct exynos_adc_priv *priv = dev_get_priv(dev);
  85. priv->regs = (struct exynos_adc_v2 *)dev_get_addr(dev);
  86. if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) {
  87. error("Dev: %s - can't get address!", dev->name);
  88. return -ENODATA;
  89. }
  90. uc_pdata->data_mask = ADC_V2_DAT_MASK;
  91. uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
  92. uc_pdata->data_timeout_us = ADC_V2_CONV_TIMEOUT_US;
  93. /* Mask available channel bits: [0:9] */
  94. uc_pdata->channel_mask = (2 << ADC_V2_MAX_CHANNEL) - 1;
  95. return 0;
  96. }
  97. static const struct adc_ops exynos_adc_ops = {
  98. .start_channel = exynos_adc_start_channel,
  99. .channel_data = exynos_adc_channel_data,
  100. .stop = exynos_adc_stop,
  101. };
  102. static const struct udevice_id exynos_adc_ids[] = {
  103. { .compatible = "samsung,exynos-adc-v2" },
  104. { }
  105. };
  106. U_BOOT_DRIVER(exynos_adc) = {
  107. .name = "exynos-adc",
  108. .id = UCLASS_ADC,
  109. .of_match = exynos_adc_ids,
  110. .ops = &exynos_adc_ops,
  111. .probe = exynos_adc_probe,
  112. .ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
  113. .priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
  114. };