pwm.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * Tegra2 pulse width frequency modulator definitions
  3. *
  4. * Copyright (c) 2011 The Chromium OS Authors.
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <fdtdec.h>
  25. #include <asm/io.h>
  26. #include <asm/arch/clock.h>
  27. #include <asm/arch/pwm.h>
  28. struct pwm_info {
  29. struct pwm_ctlr *pwm; /* Registers for our pwm controller */
  30. int pwm_node; /* PWM device tree node */
  31. } local;
  32. void pwm_enable(unsigned channel, int rate, int pulse_width, int freq_divider)
  33. {
  34. u32 reg;
  35. assert(channel < PWM_NUM_CHANNELS);
  36. /* TODO: Can we use clock_adjust_periph_pll_div() here? */
  37. clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, rate);
  38. reg = PWM_ENABLE_MASK;
  39. reg |= pulse_width << PWM_WIDTH_SHIFT;
  40. reg |= freq_divider << PWM_DIVIDER_SHIFT;
  41. writel(reg, &local.pwm[channel].control);
  42. debug("%s: channel=%d, rate=%d\n", __func__, channel, rate);
  43. }
  44. int pwm_request(const void *blob, int node, const char *prop_name)
  45. {
  46. int pwm_node;
  47. u32 data[3];
  48. if (fdtdec_get_int_array(blob, node, prop_name, data,
  49. ARRAY_SIZE(data))) {
  50. debug("%s: Cannot decode PWM property '%s'\n", __func__,
  51. prop_name);
  52. return -1;
  53. }
  54. pwm_node = fdt_node_offset_by_phandle(blob, data[0]);
  55. if (pwm_node != local.pwm_node) {
  56. debug("%s: PWM property '%s' phandle %d not recognised"
  57. "- expecting %d\n", __func__, prop_name, data[0],
  58. local.pwm_node);
  59. return -1;
  60. }
  61. if (data[1] >= PWM_NUM_CHANNELS) {
  62. debug("%s: PWM property '%s': invalid channel %u\n", __func__,
  63. prop_name, data[1]);
  64. return -1;
  65. }
  66. /*
  67. * TODO: We could maintain a list of requests, but it might not be
  68. * worth it for U-Boot.
  69. */
  70. return data[1];
  71. }
  72. int pwm_init(const void *blob)
  73. {
  74. local.pwm_node = fdtdec_next_compatible(blob, 0,
  75. COMPAT_NVIDIA_TEGRA20_PWM);
  76. if (local.pwm_node < 0) {
  77. debug("%s: Cannot find device tree node\n", __func__);
  78. return -1;
  79. }
  80. local.pwm = (struct pwm_ctlr *)fdtdec_get_addr(blob, local.pwm_node,
  81. "reg");
  82. if (local.pwm == (struct pwm_ctlr *)FDT_ADDR_T_NONE) {
  83. debug("%s: Cannot find pwm reg address\n", __func__);
  84. return -1;
  85. }
  86. debug("Tegra PWM at %p, node %d\n", local.pwm, local.pwm_node);
  87. return 0;
  88. }