bd9571mwv-regulator.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * ROHM BD9571MWV-M regulator driver
  3. *
  4. * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  11. * kind, whether expressed or implied; without even the implied warranty
  12. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License version 2 for more details.
  14. *
  15. * Based on the TPS65086 driver
  16. *
  17. * NOTE: VD09 is missing
  18. */
  19. #include <linux/module.h>
  20. #include <linux/of.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/regulator/driver.h>
  23. #include <linux/mfd/bd9571mwv.h>
  24. enum bd9571mwv_regulators { VD09, VD18, VD25, VD33, DVFS };
  25. #define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\
  26. { \
  27. .name = _name, \
  28. .of_match = of_match_ptr(_of), \
  29. .regulators_node = "regulators", \
  30. .id = _id, \
  31. .ops = &_ops, \
  32. .n_voltages = _nv, \
  33. .type = REGULATOR_VOLTAGE, \
  34. .owner = THIS_MODULE, \
  35. .vsel_reg = _vr, \
  36. .vsel_mask = _vm, \
  37. .min_uV = _min, \
  38. .uV_step = _step, \
  39. .linear_min_sel = _lmin, \
  40. }
  41. static int bd9571mwv_avs_get_moni_state(struct regulator_dev *rdev)
  42. {
  43. unsigned int val;
  44. int ret;
  45. ret = regmap_read(rdev->regmap, BD9571MWV_AVS_SET_MONI, &val);
  46. if (ret != 0)
  47. return ret;
  48. return val & BD9571MWV_AVS_SET_MONI_MASK;
  49. }
  50. static int bd9571mwv_avs_set_voltage_sel_regmap(struct regulator_dev *rdev,
  51. unsigned int sel)
  52. {
  53. int ret;
  54. ret = bd9571mwv_avs_get_moni_state(rdev);
  55. if (ret < 0)
  56. return ret;
  57. return regmap_write_bits(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret),
  58. rdev->desc->vsel_mask, sel);
  59. }
  60. static int bd9571mwv_avs_get_voltage_sel_regmap(struct regulator_dev *rdev)
  61. {
  62. unsigned int val;
  63. int ret;
  64. ret = bd9571mwv_avs_get_moni_state(rdev);
  65. if (ret < 0)
  66. return ret;
  67. ret = regmap_read(rdev->regmap, BD9571MWV_AVS_VD09_VID(ret), &val);
  68. if (ret != 0)
  69. return ret;
  70. val &= rdev->desc->vsel_mask;
  71. val >>= ffs(rdev->desc->vsel_mask) - 1;
  72. return val;
  73. }
  74. static int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev *rdev,
  75. unsigned int sel)
  76. {
  77. return regmap_write_bits(rdev->regmap, BD9571MWV_DVFS_SETVID,
  78. rdev->desc->vsel_mask, sel);
  79. }
  80. /* Operations permitted on AVS voltage regulator */
  81. static struct regulator_ops avs_ops = {
  82. .set_voltage_sel = bd9571mwv_avs_set_voltage_sel_regmap,
  83. .map_voltage = regulator_map_voltage_linear,
  84. .get_voltage_sel = bd9571mwv_avs_get_voltage_sel_regmap,
  85. .list_voltage = regulator_list_voltage_linear,
  86. };
  87. /* Operations permitted on voltage regulators */
  88. static struct regulator_ops reg_ops = {
  89. .set_voltage_sel = bd9571mwv_reg_set_voltage_sel_regmap,
  90. .map_voltage = regulator_map_voltage_linear,
  91. .get_voltage_sel = regulator_get_voltage_sel_regmap,
  92. .list_voltage = regulator_list_voltage_linear,
  93. };
  94. /* Operations permitted on voltage monitors */
  95. static struct regulator_ops vid_ops = {
  96. .map_voltage = regulator_map_voltage_linear,
  97. .get_voltage_sel = regulator_get_voltage_sel_regmap,
  98. .list_voltage = regulator_list_voltage_linear,
  99. };
  100. static struct regulator_desc regulators[] = {
  101. BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f,
  102. 0x6f, 600000, 10000, 0x3c),
  103. BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf,
  104. 16, 1625000, 25000, 0),
  105. BD9571MWV_REG("VD25", "vd25", VD25, vid_ops, BD9571MWV_VD25_VID, 0xf,
  106. 16, 2150000, 50000, 0),
  107. BD9571MWV_REG("VD33", "vd33", VD33, vid_ops, BD9571MWV_VD33_VID, 0xf,
  108. 11, 2800000, 100000, 0),
  109. BD9571MWV_REG("DVFS", "dvfs", DVFS, reg_ops,
  110. BD9571MWV_DVFS_MONIVDAC, 0x7f,
  111. 0x6f, 600000, 10000, 0x3c),
  112. };
  113. static int bd9571mwv_regulator_probe(struct platform_device *pdev)
  114. {
  115. struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent);
  116. struct regulator_config config = { };
  117. struct regulator_dev *rdev;
  118. int i;
  119. platform_set_drvdata(pdev, bd);
  120. config.dev = &pdev->dev;
  121. config.dev->of_node = bd->dev->of_node;
  122. config.driver_data = bd;
  123. config.regmap = bd->regmap;
  124. for (i = 0; i < ARRAY_SIZE(regulators); i++) {
  125. rdev = devm_regulator_register(&pdev->dev, &regulators[i],
  126. &config);
  127. if (IS_ERR(rdev)) {
  128. dev_err(bd->dev, "failed to register %s regulator\n",
  129. pdev->name);
  130. return PTR_ERR(rdev);
  131. }
  132. }
  133. return 0;
  134. }
  135. static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
  136. { "bd9571mwv-regulator", },
  137. { /* sentinel */ }
  138. };
  139. MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
  140. static struct platform_driver bd9571mwv_regulator_driver = {
  141. .driver = {
  142. .name = "bd9571mwv-regulator",
  143. },
  144. .probe = bd9571mwv_regulator_probe,
  145. .id_table = bd9571mwv_regulator_id_table,
  146. };
  147. module_platform_driver(bd9571mwv_regulator_driver);
  148. MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
  149. MODULE_DESCRIPTION("BD9571MWV Regulator driver");
  150. MODULE_LICENSE("GPL v2");