environmentalTemperatureAnalysis.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * clkt_clksel.c - OMAP2/3/4 clksel clock functions
  3. *
  4. * Copyright (C) 2005-2008 Texas Instruments, Inc.
  5. * Copyright (C) 2004-2010 Nokia Corporation
  6. *
  7. * Contacts:
  8. * Richard Woodruff <r-woodruff2@ti.com>
  9. * Paul Walmsley
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. *
  15. *
  16. * clksel clocks are clocks that do not have a fixed parent, or that
  17. * can divide their parent's rate, or possibly both at the same time, based
  18. * on the contents of a hardware register bitfield.
  19. *
  20. * All of the various mux and divider settings can be encoded into
  21. * struct clksel* data structures, and then these can be autogenerated
  22. * from some hardware database for each new chip generation. This
  23. * should avoid the need to write, review, and validate a lot of new
  24. * clock code for each new chip, since it can be exported from the SoC
  25. * design flow. This is now done on OMAP4.
  26. *
  27. * The fusion of mux and divider clocks is a software creation. In
  28. * hardware reality, the multiplexer (parent selection) and the
  29. * divider exist separately. XXX At some point these clksel clocks
  30. * should be split into "divider" clocks and "mux" clocks to better
  31. * match the hardware.
  32. *
  33. * (The name "clksel" comes from the name of the corresponding
  34. * register field in the OMAP2/3 family of SoCs.)
  35. *
  36. * XXX Currently these clocks are only used in the OMAP2/3/4 code, but
  37. * many of the OMAP1 clocks should be convertible to use this
  38. * mechanism.
  39. */
  40. #undef DEBUG
  41. #include <linux/kernel.h>
  42. #include <linux/errno.h>
  43. #include <linux/clk-provider.h>
  44. #include <linux/io.h>
  45. #include <linux/bug.h>
  46. #include "clock.h"
  47. /* Private functions */
  48. /**
  49. * _get_clksel_by_parent() - return clksel struct for a given clk & parent
  50. * @clk: OMAP struct clk ptr to inspect
  51. * @src_clk: OMAP struct clk ptr of the parent clk to search for
  52. *
  53. * Scan the struct clksel array associated with the clock to find
  54. * the element associated with the supplied parent clock address.
  55. * Returns a pointer to the struct clksel on success or NULL on error.
  56. */
  57. static const struct clksel *_get_clksel_by_parent(struct clk_hw_omap *clk,
  58. struct clk *src_clk)
  59. {
  60. const struct clksel *clks;
  61. if (!src_clk)
  62. return NULL;
  63. for (clks = clk->clksel; clks->parent; clks++)
  64. if (clks->parent == src_clk)
  65. break; /* Found the requested parent */
  66. if (!clks->parent) {
  67. /* This indicates a data problem */
  68. WARN(1, "clock: %s: could not find parent clock %s in clksel array\n",
  69. __clk_get_name(clk->hw.clk), __clk_get_name(src_clk));
  70. return NULL;
  71. }
  72. return clks;
  73. }
  74. /**
  75. * _write_clksel_reg() - program a clock's clksel register in hardware
  76. * @clk: struct clk * to program
  77. * @v: clksel bitfield value to program (with LSB at bit 0)
  78. *
  79. * Shift the clksel register bitfield value @v to its appropriate
  80. * location in the clksel register and write it in. This function
  81. * will ensure that the write to the clksel_reg reaches its
  82. * destination before returning -- important since PRM and CM register
  83. * accesses can be quite slow compared to ARM cycles -- but does not
  84. * take into account any time the hardware might take to switch the
  85. * clock source.
  86. */
  87. static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val)
  88. {
  89. u32 v;
  90. v = __raw_readl(clk->clksel_reg);
  91. v &= ~clk->clksel_mask;
  92. v |= field_val << __ffs(clk->clksel_mask);
  93. __raw_writel(v, clk->clksel_reg);
  94. v = __raw_readl(clk->clksel_reg); /* OCP barrier */
  95. }
  96. /**
  97. * _clksel_to_divisor() - turn clksel field value into integer divider
  98. * @clk: OMAP struct clk to use
  99. * @field_val: register field value to find
  100. *
  101. * Given a struct clk of a rate-selectable clksel clock, and a register field
  102. * value to search for, find the corresponding clock divisor. The register
  103. * field value should be pre-masked and shifted down so the LSB is at bit 0
  104. * before calling. Returns 0 on error or returns the actual integer divisor
  105. * upon success.
  106. */
  107. static u32 _clksel_to_divisor(struct clk_hw_omap *clk, u32 field_val)
  108. {
  109. const struct clksel *clks;
  110. const struct clksel_rate *clkr;
  111. struct clk *parent;
  112. parent = __clk_get_parent(clk->hw.clk);
  113. clks = _get_clksel_by_parent(clk, parent);
  114. if (!clks)
  115. return 0;
  116. for (clkr = clks->rates; clkr->div; clkr++) {
  117. if (!(clkr->flags & cpu_mask))
  118. continue;
  119. if (clkr->val == field_val)
  120. break;
  121. }
  122. if (!clkr->div) {
  123. /* This indicates a data error */
  124. WARN(1, "clock: %s: could not find fieldval %d for parent %s\n",
  125. __clk_get_name(clk->hw.clk), field_val,
  126. __clk_get_name(parent));
  127. return 0;
  128. }
  129. return clkr->div;
  130. }
  131. /**
  132. * _divisor_to_clksel() - turn clksel integer divisor into a field value
  133. * @clk: OMAP struct clk to use
  134. * @div: integer divisor to search for
  135. *
  136. * Given a struct clk of a rate-selectable clksel clock, and a clock
  137. * divisor, find the corresponding register field value. Returns the
  138. * register field value _before_ left-shifting (i.e., LSB is at bit
  139. * 0); or returns 0xFFFFFFFF (~0) upon error.
  140. */
  141. static u32 _divisor_to_clksel(struct clk_hw_omap *clk, u32 div)
  142. {
  143. const struct clksel *clks;
  144. const struct clksel_rate *clkr;
  145. struct clk *parent;
  146. /* should never happen */
  147. WARN_ON(div == 0);
  148. parent = __clk_get_parent(clk->hw.clk);
  149. clks = _get_clksel_by_parent(clk, parent);
  150. if (!clks)
  151. return ~0;
  152. for (clkr = clks->rates; clkr->div; clkr++) {
  153. if (!(clkr->flags & cpu_mask))
  154. continue;
  155. if (clkr->div == div)
  156. break;
  157. }
  158. if (!clkr->div) {
  159. pr_err("clock: %s: could not find divisor %d for parent %s\n",
  160. __clk_get_name(clk->hw.clk), div,
  161. __clk_get_name(parent));
  162. return ~0;
  163. }
  164. return clkr->val;
  165. }
  166. /**
  167. * _read_divisor() - get current divisor applied to parent clock (from hdwr)
  168. * @clk: OMAP struct clk to use.
  169. *
  170. * Read the current divisor register value for @clk that is programmed
  171. * into the hardware, convert it into the actual divisor value, and
  172. * return it; or return 0 on error.
  173. */
  174. static u32 _read_divisor(struct clk_hw_omap *clk)
  175. {