pwm.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * Tegra pulse width frequency modulator definitions
  3. *
  4. * Copyright (c) 2011 The Chromium OS Authors.
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <fdtdec.h>
  10. #include <asm/io.h>
  11. #include <asm/arch/clock.h>
  12. #include <asm/arch/pwm.h>
  13. struct pwm_info {
  14. struct pwm_ctlr *pwm; /* Registers for our pwm controller */
  15. int pwm_node; /* PWM device tree node */
  16. } local;
  17. void pwm_enable(unsigned channel, int rate, int pulse_width, int freq_divider)
  18. {
  19. u32 reg;
  20. assert(channel < PWM_NUM_CHANNELS);
  21. /* TODO: Can we use clock_adjust_periph_pll_div() here? */
  22. clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, rate);
  23. reg = PWM_ENABLE_MASK;
  24. reg |= pulse_width << PWM_WIDTH_SHIFT;
  25. reg |= freq_divider << PWM_DIVIDER_SHIFT;
  26. writel(reg, &local.pwm[channel].control);
  27. debug("%s: channel=%d, rate=%d\n", __func__, channel, rate);
  28. }
  29. int pwm_request(const void *blob, int node, const char *prop_name)
  30. {
  31. int pwm_node;
  32. u32 data[3];
  33. if (fdtdec_get_int_array(blob, node, prop_name, data,
  34. ARRAY_SIZE(data))) {
  35. debug("%s: Cannot decode PWM property '%s'\n", __func__,
  36. prop_name);
  37. return -1;
  38. }
  39. pwm_node = fdt_node_offset_by_phandle(blob, data[0]);
  40. if (pwm_node != local.pwm_node) {
  41. debug("%s: PWM property '%s' phandle %d not recognised"
  42. "- expecting %d\n", __func__, prop_name, data[0],
  43. local.pwm_node);
  44. return -1;
  45. }
  46. if (data[1] >= PWM_NUM_CHANNELS) {
  47. debug("%s: PWM property '%s': invalid channel %u\n", __func__,
  48. prop_name, data[1]);
  49. return -1;
  50. }
  51. /*
  52. * TODO: We could maintain a list of requests, but it might not be
  53. * worth it for U-Boot.
  54. */
  55. return data[1];
  56. }
  57. int pwm_init(const void *blob)
  58. {
  59. local.pwm_node = fdtdec_next_compatible(blob, 0,
  60. COMPAT_NVIDIA_TEGRA20_PWM);
  61. if (local.pwm_node < 0) {
  62. debug("%s: Cannot find device tree node\n", __func__);
  63. return -1;
  64. }
  65. local.pwm = (struct pwm_ctlr *)fdtdec_get_addr(blob, local.pwm_node,
  66. "reg");
  67. if (local.pwm == (struct pwm_ctlr *)FDT_ADDR_T_NONE) {
  68. debug("%s: Cannot find pwm reg address\n", __func__);
  69. return -1;
  70. }
  71. debug("Tegra PWM at %p, node %d\n", local.pwm, local.pwm_node);
  72. return 0;
  73. }