qcom_smd-regulator.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * Copyright (c) 2015, Sony Mobile Communications AB.
  3. * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 and
  7. * only version 2 as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <linux/of_device.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/regulator/driver.h>
  19. #include <linux/regulator/machine.h>
  20. #include <linux/regulator/of_regulator.h>
  21. #include <linux/soc/qcom/smd-rpm.h>
  22. struct qcom_rpm_reg {
  23. struct device *dev;
  24. struct qcom_smd_rpm *rpm;
  25. u32 type;
  26. u32 id;
  27. struct regulator_desc desc;
  28. int is_enabled;
  29. int uV;
  30. };
  31. struct rpm_regulator_req {
  32. u32 key;
  33. u32 nbytes;
  34. u32 value;
  35. };
  36. #define RPM_KEY_SWEN 0x6e657773 /* "swen" */
  37. #define RPM_KEY_UV 0x00007675 /* "uv" */
  38. #define RPM_KEY_MA 0x0000616d /* "ma" */
  39. static int rpm_reg_write_active(struct qcom_rpm_reg *vreg,
  40. struct rpm_regulator_req *req,
  41. size_t size)
  42. {
  43. return qcom_rpm_smd_write(vreg->rpm,
  44. QCOM_SMD_RPM_ACTIVE_STATE,
  45. vreg->type,
  46. vreg->id,
  47. req, size);
  48. }
  49. static int rpm_reg_enable(struct regulator_dev *rdev)
  50. {
  51. struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
  52. struct rpm_regulator_req req;
  53. int ret;
  54. req.key = RPM_KEY_SWEN;
  55. req.nbytes = sizeof(u32);
  56. req.value = 1;
  57. ret = rpm_reg_write_active(vreg, &req, sizeof(req));
  58. if (!ret)
  59. vreg->is_enabled = 1;
  60. return ret;
  61. }
  62. static int rpm_reg_is_enabled(struct regulator_dev *rdev)
  63. {
  64. struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
  65. return vreg->is_enabled;
  66. }
  67. static int rpm_reg_disable(struct regulator_dev *rdev)
  68. {
  69. struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
  70. struct rpm_regulator_req req;
  71. int ret;
  72. req.key = RPM_KEY_SWEN;
  73. req.nbytes = sizeof(u32);
  74. req.value = 0;
  75. ret = rpm_reg_write_active(vreg, &req, sizeof(req));
  76. if (!ret)
  77. vreg->is_enabled = 0;
  78. return ret;
  79. }
  80. static int rpm_reg_get_voltage(struct regulator_dev *rdev)
  81. {
  82. struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
  83. return vreg->uV;
  84. }
  85. static int rpm_reg_set_voltage(struct regulator_dev *rdev,
  86. int min_uV,
  87. int max_uV,
  88. unsigned *selector)
  89. {
  90. struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
  91. struct rpm_regulator_req req;
  92. int ret = 0;
  93. req.key = RPM_KEY_UV;
  94. req.nbytes = sizeof(u32);
  95. req.value = min_uV;
  96. ret = rpm_reg_write_active(vreg, &req, sizeof(req));
  97. if (!ret)
  98. vreg->uV = min_uV;
  99. return ret;
  100. }
  101. static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA)
  102. {
  103. struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
  104. struct rpm_regulator_req req;
  105. req.key = RPM_KEY_MA;
  106. req.nbytes = sizeof(u32);
  107. req.value = load_uA;
  108. return rpm_reg_write_active(vreg, &req, sizeof(req));
  109. }
  110. static const struct regulator_ops rpm_smps_ldo_ops = {
  111. .enable = rpm_reg_enable,
  112. .disable = rpm_reg_disable,
  113. .is_enabled = rpm_reg_is_enabled,
  114. .get_voltage = rpm_reg_get_voltage,
  115. .set_voltage = rpm_reg_set_voltage,
  116. .set_load = rpm_reg_set_load,
  117. };
  118. static const struct regulator_ops rpm_switch_ops = {
  119. .enable = rpm_reg_enable,
  120. .disable = rpm_reg_disable,
  121. .is_enabled = rpm_reg_is_enabled,
  122. };
  123. static const struct regulator_desc pm8x41_hfsmps = {
  124. .linear_ranges = (struct regulator_linear_range[]) {
  125. REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500),
  126. REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
  127. },
  128. .n_linear_ranges = 2,
  129. .n_voltages = 159,
  130. .ops = &rpm_smps_ldo_ops,
  131. };
  132. static const struct regulator_desc pm8841_ftsmps = {
  133. .linear_ranges = (struct regulator_linear_range[]) {
  134. REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
  135. REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
  136. },
  137. .n_linear_ranges = 2,
  138. .n_voltages = 340,
  139. .ops = &rpm_smps_ldo_ops,
  140. };
  141. static const struct regulator_desc pm8941_boost = {
  142. .linear_ranges = (struct regulator_linear_range[]) {
  143. REGULATOR_LINEAR_RANGE(4000000, 0, 15, 100000),
  144. },
  145. .n_linear_ranges = 1,
  146. .n_voltages = 16,
  147. .ops = &rpm_smps_ldo_ops,
  148. };
  149. static const struct regulator_desc pm8941_pldo = {
  150. .linear_ranges = (struct regulator_linear_range[]) {
  151. REGULATOR_LINEAR_RANGE( 750000, 0, 30, 25000),
  152. REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
  153. },
  154. .n_linear_ranges = 2,
  155. .n_voltages = 100,
  156. .ops = &rpm_smps_ldo_ops,
  157. };
  158. static const struct regulator_desc pm8941_nldo = {
  159. .linear_ranges = (struct regulator_linear_range[]) {
  160. REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
  161. },
  162. .n_linear_ranges = 1,
  163. .n_voltages = 64,
  164. .ops = &rpm_smps_ldo_ops,
  165. };
  166. static const struct regulator_desc pm8941_lnldo = {
  167. .fixed_uV = 1740000,
  168. .n_voltages = 1,
  169. .ops = &rpm_smps_ldo_ops,
  170. };
  171. static const struct regulator_desc pm8941_switch = {
  172. .ops = &rpm_switch_ops,
  173. };
  174. struct rpm_regulator_data {
  175. const char *name;
  176. u32 type;
  177. u32 id;
  178. const struct regulator_desc *desc;
  179. const char *supply;
  180. };
  181. static const struct rpm_regulator_data rpm_pm8841_regulators[] = {
  182. { "s1", QCOM_SMD_RPM_SMPB, 1, &pm8x41_hfsmps, "vdd_s1" },
  183. { "s2", QCOM_SMD_RPM_SMPB, 2, &pm8841_ftsmps, "vdd_s2" },
  184. { "s3", QCOM_SMD_RPM_SMPB, 3, &pm8x41_hfsmps, "vdd_s3" },
  185. { "s4", QCOM_SMD_RPM_SMPB, 4, &pm8841_ftsmps, "vdd_s4" },
  186. { "s5", QCOM_SMD_RPM_SMPB, 5, &pm8841_ftsmps, "vdd_s5" },
  187. { "s6", QCOM_SMD_RPM_SMPB, 6, &pm8841_ftsmps, "vdd_s6" },
  188. { "s7", QCOM_SMD_RPM_SMPB, 7, &pm8841_ftsmps, "vdd_s7" },
  189. { "s8", QCOM_SMD_RPM_SMPB, 8, &pm8841_ftsmps, "vdd_s8" },
  190. {}
  191. };
  192. static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
  193. { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
  194. { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
  195. { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8x41_hfsmps, "vdd_s3" },
  196. { "s4", QCOM_SMD_RPM_BOOST, 1, &pm8941_boost },
  197. { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8941_nldo, "vdd_l1_l3" },
  198. { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8941_nldo, "vdd_l2_lvs1_2_3" },
  199. { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8941_nldo, "vdd_l1_l3" },
  200. { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8941_nldo, "vdd_l4_l11" },
  201. { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8941_lnldo, "vdd_l5_l7" },
  202. { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8941_pldo, "vdd_l6_l12_l14_l15" },
  203. { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8941_lnldo, "vdd_l5_l7" },
  204. { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8941_pldo, "vdd_l8_l16_l18_l19" },
  205. { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8941_pldo, "vdd_l9_l10_l17_l22" },
  206. { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8941_pldo, "vdd_l9_l10_l17_l22" },
  207. { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8941_nldo, "vdd_l4_l11" },
  208. { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8941_pldo, "vdd_l6_l12_l14_l15" },
  209. { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8941_pldo, "vdd_l13_l20_l23_l24" },
  210. { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8941_pldo, "vdd_l6_l12_l14_l15" },
  211. { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8941_pldo, "vdd_l6_l12_l14_l15" },
  212. { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8941_pldo, "vdd_l8_l16_l18_l19" },
  213. { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8941_pldo, "vdd_l9_l10_l17_l22" },
  214. { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8941_pldo, "vdd_l8_l16_l18_l19" },
  215. { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8941_pldo, "vdd_l8_l16_l18_l19" },
  216. { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8941_pldo, "vdd_l13_l20_l23_l24" },
  217. { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8941_pldo, "vdd_l21" },
  218. { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8941_pldo, "vdd_l9_l10_l17_l22" },
  219. { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8941_pldo, "vdd_l13_l20_l23_l24" },
  220. { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8941_pldo, "vdd_l13_l20_l23_l24" },
  221. { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8941_switch, "vdd_l2_lvs1_2_3" },
  222. { "lvs2", QCOM_SMD_RPM_VSA, 2, &pm8941_switch, "vdd_l2_lvs1_2_3" },
  223. { "lvs3", QCOM_SMD_RPM_VSA, 3, &pm8941_switch, "vdd_l2_lvs1_2_3" },
  224. { "5vs1", QCOM_SMD_RPM_VSA, 4, &pm8941_switch, "vin_5vs" },
  225. { "5vs2", QCOM_SMD_RPM_VSA, 5, &pm8941_switch, "vin_5vs" },
  226. {}
  227. };
  228. static const struct of_device_id rpm_of_match[] = {
  229. { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
  230. { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
  231. {}
  232. };
  233. MODULE_DEVICE_TABLE(of, rpm_of_match);
  234. static int rpm_reg_probe(struct platform_device *pdev)
  235. {
  236. const struct rpm_regulator_data *reg;
  237. const struct of_device_id *match;
  238. struct regulator_config config = { };
  239. struct regulator_dev *rdev;
  240. struct qcom_rpm_reg *vreg;
  241. struct qcom_smd_rpm *rpm;
  242. rpm = dev_get_drvdata(pdev->dev.parent);
  243. if (!rpm) {
  244. dev_err(&pdev->dev, "unable to retrieve handle to rpm\n");
  245. return -ENODEV;
  246. }
  247. match = of_match_device(rpm_of_match, &pdev->dev);
  248. for (reg = match->data; reg->name; reg++) {
  249. vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
  250. if (!vreg)
  251. return -ENOMEM;
  252. vreg->dev = &pdev->dev;
  253. vreg->type = reg->type;
  254. vreg->id = reg->id;
  255. vreg->rpm = rpm;
  256. memcpy(&vreg->desc, reg->desc, sizeof(vreg->desc));
  257. vreg->desc.id = -1;
  258. vreg->desc.owner = THIS_MODULE;
  259. vreg->desc.type = REGULATOR_VOLTAGE;
  260. vreg->desc.name = reg->name;
  261. vreg->desc.supply_name = reg->supply;
  262. vreg->desc.of_match = reg->name;
  263. config.dev = &pdev->dev;
  264. config.driver_data = vreg;
  265. rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config);
  266. if (IS_ERR(rdev)) {
  267. dev_err(&pdev->dev, "failed to register %s\n", reg->name);
  268. return PTR_ERR(rdev);
  269. }
  270. }
  271. return 0;
  272. }
  273. static struct platform_driver rpm_reg_driver = {
  274. .probe = rpm_reg_probe,
  275. .driver = {
  276. .name = "qcom_rpm_smd_regulator",
  277. .of_match_table = rpm_of_match,
  278. },
  279. };
  280. static int __init rpm_reg_init(void)
  281. {
  282. return platform_driver_register(&rpm_reg_driver);
  283. }
  284. subsys_initcall(rpm_reg_init);
  285. static void __exit rpm_reg_exit(void)
  286. {
  287. platform_driver_unregister(&rpm_reg_driver);
  288. }
  289. module_exit(rpm_reg_exit)
  290. MODULE_DESCRIPTION("Qualcomm RPM regulator driver");
  291. MODULE_LICENSE("GPL v2");