armada_thermal.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Marvell Armada 370/XP thermal sensor driver
  3. *
  4. * Copyright (C) 2013 Marvell
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16. #include <linux/device.h>
  17. #include <linux/err.h>
  18. #include <linux/io.h>
  19. #include <linux/kernel.h>
  20. #include <linux/of.h>
  21. #include <linux/module.h>
  22. #include <linux/delay.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/of_device.h>
  25. #include <linux/thermal.h>
  26. #define THERMAL_VALID_MASK 0x1
  27. /* Thermal Manager Control and Status Register */
  28. #define PMU_TDC0_SW_RST_MASK (0x1 << 1)
  29. #define PMU_TM_DISABLE_OFFS 0
  30. #define PMU_TM_DISABLE_MASK (0x1 << PMU_TM_DISABLE_OFFS)
  31. #define PMU_TDC0_REF_CAL_CNT_OFFS 11
  32. #define PMU_TDC0_REF_CAL_CNT_MASK (0x1ff << PMU_TDC0_REF_CAL_CNT_OFFS)
  33. #define PMU_TDC0_OTF_CAL_MASK (0x1 << 30)
  34. #define PMU_TDC0_START_CAL_MASK (0x1 << 25)
  35. #define A375_Z1_CAL_RESET_LSB 0x8011e214
  36. #define A375_Z1_CAL_RESET_MSB 0x30a88019
  37. #define A375_Z1_WORKAROUND_BIT BIT(9)
  38. #define A375_UNIT_CONTROL_SHIFT 27
  39. #define A375_UNIT_CONTROL_MASK 0x7
  40. #define A375_READOUT_INVERT BIT(15)
  41. #define A375_HW_RESETn BIT(8)
  42. #define A380_HW_RESET BIT(8)
  43. struct armada_thermal_data;
  44. /* Marvell EBU Thermal Sensor Dev Structure */
  45. struct armada_thermal_priv {
  46. void __iomem *sensor;
  47. void __iomem *control;
  48. struct armada_thermal_data *data;
  49. };
  50. struct armada_thermal_data {
  51. /* Initialize the sensor */
  52. void (*init_sensor)(struct platform_device *pdev,
  53. struct armada_thermal_priv *);
  54. /* Test for a valid sensor value (optional) */
  55. bool (*is_valid)(struct armada_thermal_priv *);
  56. /* Formula coeficients: temp = (b + m * reg) / div */
  57. unsigned long coef_b;
  58. unsigned long coef_m;
  59. unsigned long coef_div;
  60. bool inverted;
  61. /* Register shift and mask to access the sensor temperature */
  62. unsigned int temp_shift;
  63. unsigned int temp_mask;
  64. unsigned int is_valid_shift;
  65. };
  66. static void armadaxp_init_sensor(struct platform_device *pdev,
  67. struct armada_thermal_priv *priv)
  68. {
  69. unsigned long reg;
  70. reg = readl_relaxed(priv->control);
  71. reg |= PMU_TDC0_OTF_CAL_MASK;
  72. writel(reg, priv->control);
  73. /* Reference calibration value */
  74. reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
  75. reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
  76. writel(reg, priv->control);
  77. /* Reset the sensor */
  78. reg = readl_relaxed(priv->control);
  79. writel((reg | PMU_TDC0_SW_RST_MASK), priv->control);
  80. writel(reg, priv->control);
  81. /* Enable the sensor */
  82. reg = readl_relaxed(priv->sensor);
  83. reg &= ~PMU_TM_DISABLE_MASK;
  84. writel(reg, priv->sensor);
  85. }
  86. static void armada370_init_sensor(struct platform_device *pdev,
  87. struct armada_thermal_priv *priv)
  88. {
  89. unsigned long reg;
  90. reg = readl_relaxed(priv->control);
  91. reg |= PMU_TDC0_OTF_CAL_MASK;
  92. writel(reg, priv->control);
  93. /* Reference calibration value */
  94. reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
  95. reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
  96. writel(reg, priv->control);
  97. reg &= ~PMU_TDC0_START_CAL_MASK;
  98. writel(reg, priv->control);
  99. mdelay(10);
  100. }
  101. static void armada375_init_sensor(struct platform_device *pdev,
  102. struct armada_thermal_priv *priv)
  103. {
  104. unsigned long reg;
  105. bool quirk_needed =
  106. !!of_device_is_compatible(pdev->dev.of_node,
  107. "marvell,armada375-z1-thermal");
  108. if (quirk_needed) {
  109. /* Ensure these registers have the default (reset) values */
  110. writel(A375_Z1_CAL_RESET_LSB, priv->control);
  111. writel(A375_Z1_CAL_RESET_MSB, priv->control + 0x4);
  112. }
  113. reg = readl(priv->control + 4);
  114. reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT);
  115. reg &= ~A375_READOUT_INVERT;
  116. reg &= ~A375_HW_RESETn;
  117. if (quirk_needed)
  118. reg |= A375_Z1_WORKAROUND_BIT;
  119. writel(reg, priv->control + 4);
  120. mdelay(20);
  121. reg |= A375_HW_RESETn;
  122. writel(reg, priv->control + 4);
  123. mdelay(50);
  124. }
  125. static void armada380_init_sensor(struct platform_device *pdev,
  126. struct armada_thermal_priv *priv)
  127. {
  128. unsigned long reg = readl_relaxed(priv->control);
  129. /* Reset hardware once */
  130. if (!(reg & A380_HW_RESET)) {
  131. reg |= A380_HW_RESET;
  132. writel(reg, priv->control);
  133. mdelay(10);
  134. }
  135. }
  136. static bool armada_is_valid(struct armada_thermal_priv *priv)
  137. {
  138. unsigned long reg = readl_relaxed(priv->sensor);
  139. return (reg >> priv->data->is_valid_shift) & THERMAL_VALID_MASK;
  140. }
  141. static int armada_get_temp(struct thermal_zone_device *thermal,
  142. unsigned long *temp)
  143. {
  144. struct armada_thermal_priv *priv = thermal->devdata;
  145. unsigned long reg;
  146. unsigned long m, b, div;
  147. /* Valid check */
  148. if (priv->data->is_valid && !priv->data->is_valid(priv)) {
  149. dev_err(&thermal->device,
  150. "Temperature sensor reading not valid\n");
  151. return -EIO;
  152. }
  153. reg = readl_relaxed(priv->sensor);
  154. reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask;
  155. /* Get formula coeficients */
  156. b = priv->data->coef_b;
  157. m = priv->data->coef_m;
  158. div = priv->data->coef_div;
  159. if (priv->data->inverted)
  160. *temp = ((m * reg) - b) / div;
  161. else
  162. *temp = (b - (m * reg)) / div;
  163. return 0;
  164. }
  165. static struct thermal_zone_device_ops ops = {
  166. .get_temp = armada_get_temp,
  167. };
  168. static const struct armada_thermal_data armadaxp_data = {
  169. .init_sensor = armadaxp_init_sensor,
  170. .temp_shift = 10,
  171. .temp_mask = 0x1ff,
  172. .coef_b = 3153000000UL,
  173. .coef_m = 10000000UL,
  174. .coef_div = 13825,
  175. };
  176. static const struct armada_thermal_data armada370_data = {
  177. .is_valid = armada_is_valid,
  178. .init_sensor = armada370_init_sensor,
  179. .is_valid_shift = 9,
  180. .temp_shift = 10,
  181. .temp_mask = 0x1ff,
  182. .coef_b = 3153000000UL,
  183. .coef_m = 10000000UL,
  184. .coef_div = 13825,
  185. };
  186. static const struct armada_thermal_data armada375_data = {
  187. .is_valid = armada_is_valid,
  188. .init_sensor = armada375_init_sensor,
  189. .is_valid_shift = 10,
  190. .temp_shift = 0,
  191. .temp_mask = 0x1ff,
  192. .coef_b = 3171900000UL,
  193. .coef_m = 10000000UL,
  194. .coef_div = 13616,
  195. };
  196. static const struct armada_thermal_data armada380_data = {
  197. .is_valid = armada_is_valid,
  198. .init_sensor = armada380_init_sensor,
  199. .is_valid_shift = 10,
  200. .temp_shift = 0,
  201. .temp_mask = 0x3ff,
  202. .coef_b = 1169498786UL,
  203. .coef_m = 2000000UL,
  204. .coef_div = 4289,
  205. .inverted = true,
  206. };
  207. static const struct of_device_id armada_thermal_id_table[] = {
  208. {
  209. .compatible = "marvell,armadaxp-thermal",
  210. .data = &armadaxp_data,
  211. },
  212. {
  213. .compatible = "marvell,armada370-thermal",
  214. .data = &armada370_data,
  215. },
  216. {
  217. .compatible = "marvell,armada375-thermal",
  218. .data = &armada375_data,
  219. },
  220. {
  221. .compatible = "marvell,armada375-z1-thermal",
  222. .data = &armada375_data,
  223. },
  224. {
  225. .compatible = "marvell,armada380-thermal",
  226. .data = &armada380_data,
  227. },
  228. {
  229. /* sentinel */
  230. },
  231. };
  232. MODULE_DEVICE_TABLE(of, armada_thermal_id_table);
  233. static int armada_thermal_probe(struct platform_device *pdev)
  234. {
  235. struct thermal_zone_device *thermal;
  236. const struct of_device_id *match;
  237. struct armada_thermal_priv *priv;
  238. struct resource *res;
  239. match = of_match_device(armada_thermal_id_table, &pdev->dev);
  240. if (!match)
  241. return -ENODEV;
  242. priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  243. if (!priv)
  244. return -ENOMEM;
  245. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  246. priv->sensor = devm_ioremap_resource(&pdev->dev, res);
  247. if (IS_ERR(priv->sensor))
  248. return PTR_ERR(priv->sensor);
  249. res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  250. priv->control = devm_ioremap_resource(&pdev->dev, res);
  251. if (IS_ERR(priv->control))
  252. return PTR_ERR(priv->control);
  253. priv->data = (struct armada_thermal_data *)match->data;
  254. priv->data->init_sensor(pdev, priv);
  255. thermal = thermal_zone_device_register("armada_thermal", 0, 0,
  256. priv, &ops, NULL, 0, 0);
  257. if (IS_ERR(thermal)) {
  258. dev_err(&pdev->dev,
  259. "Failed to register thermal zone device\n");
  260. return PTR_ERR(thermal);
  261. }
  262. platform_set_drvdata(pdev, thermal);
  263. return 0;
  264. }
  265. static int armada_thermal_exit(struct platform_device *pdev)
  266. {
  267. struct thermal_zone_device *armada_thermal =
  268. platform_get_drvdata(pdev);
  269. thermal_zone_device_unregister(armada_thermal);
  270. return 0;
  271. }
  272. static struct platform_driver armada_thermal_driver = {
  273. .probe = armada_thermal_probe,
  274. .remove = armada_thermal_exit,
  275. .driver = {
  276. .name = "armada_thermal",
  277. .owner = THIS_MODULE,
  278. .of_match_table = armada_thermal_id_table,
  279. },
  280. };
  281. module_platform_driver(armada_thermal_driver);
  282. MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
  283. MODULE_DESCRIPTION("Armada 370/XP thermal driver");
  284. MODULE_LICENSE("GPL v2");