exynos-adc.c 3.3 KB

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