tps65911-comparator.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * tps65910.c -- TI TPS6591x
  3. *
  4. * Copyright 2010 Texas Instruments Inc.
  5. *
  6. * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/slab.h>
  18. #include <linux/err.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/debugfs.h>
  21. #include <linux/gpio.h>
  22. #include <linux/mfd/tps65910.h>
  23. #define COMP1 0
  24. #define COMP2 1
  25. /* Comparator 1 voltage selection table in millivolts */
  26. static const u16 COMP_VSEL_TABLE[] = {
  27. 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
  28. 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
  29. 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450,
  30. 3500,
  31. };
  32. struct comparator {
  33. const char *name;
  34. int reg;
  35. int uV_max;
  36. const u16 *vsel_table;
  37. };
  38. static struct comparator tps_comparators[] = {
  39. {
  40. .name = "COMP1",
  41. .reg = TPS65911_VMBCH,
  42. .uV_max = 3500,
  43. .vsel_table = COMP_VSEL_TABLE,
  44. },
  45. {
  46. .name = "COMP2",
  47. .reg = TPS65911_VMBCH2,
  48. .uV_max = 3500,
  49. .vsel_table = COMP_VSEL_TABLE,
  50. },
  51. };
  52. static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage)
  53. {
  54. struct comparator tps_comp = tps_comparators[id];
  55. int curr_voltage = 0;
  56. int ret;
  57. u8 index = 0, val;
  58. while (curr_voltage < tps_comp.uV_max) {
  59. curr_voltage = tps_comp.vsel_table[index];
  60. if (curr_voltage >= voltage)
  61. break;
  62. else if (curr_voltage < voltage)
  63. index ++;
  64. }
  65. if (curr_voltage > tps_comp.uV_max)
  66. return -EINVAL;
  67. val = index << 1;
  68. ret = tps65910_reg_write(tps65910, tps_comp.reg, val);
  69. return ret;
  70. }
  71. static int comp_threshold_get(struct tps65910 *tps65910, int id)
  72. {
  73. struct comparator tps_comp = tps_comparators[id];
  74. unsigned int val;
  75. int ret;
  76. ret = tps65910_reg_read(tps65910, tps_comp.reg, &val);
  77. if (ret < 0)
  78. return ret;
  79. val >>= 1;
  80. return tps_comp.vsel_table[val];
  81. }
  82. static ssize_t comp_threshold_show(struct device *dev,
  83. struct device_attribute *attr, char *buf)
  84. {
  85. struct tps65910 *tps65910 = dev_get_drvdata(dev->parent);
  86. struct attribute comp_attr = attr->attr;
  87. int id, uVolt;
  88. if (!strcmp(comp_attr.name, "comp1_threshold"))
  89. id = COMP1;
  90. else if (!strcmp(comp_attr.name, "comp2_threshold"))
  91. id = COMP2;
  92. else
  93. return -EINVAL;
  94. uVolt = comp_threshold_get(tps65910, id);
  95. return sprintf(buf, "%d\n", uVolt);
  96. }
  97. static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL);
  98. static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);
  99. static int tps65911_comparator_probe(struct platform_device *pdev)
  100. {
  101. struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
  102. struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
  103. int ret;
  104. ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold);
  105. if (ret < 0) {
  106. dev_err(&pdev->dev, "cannot set COMP1 threshold\n");
  107. return ret;
  108. }
  109. ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold);
  110. if (ret < 0) {
  111. dev_err(&pdev->dev, "cannot set COMP2 threshold\n");
  112. return ret;
  113. }
  114. /* Create sysfs entry */
  115. ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold);
  116. if (ret < 0)
  117. dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n");
  118. ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold);
  119. if (ret < 0)
  120. dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n");
  121. return ret;
  122. }
  123. static int tps65911_comparator_remove(struct platform_device *pdev)
  124. {
  125. struct tps65910 *tps65910;
  126. tps65910 = dev_get_drvdata(pdev->dev.parent);
  127. device_remove_file(&pdev->dev, &dev_attr_comp2_threshold);
  128. device_remove_file(&pdev->dev, &dev_attr_comp1_threshold);
  129. return 0;
  130. }
  131. static struct platform_driver tps65911_comparator_driver = {
  132. .driver = {
  133. .name = "tps65911-comparator",
  134. },
  135. .probe = tps65911_comparator_probe,
  136. .remove = tps65911_comparator_remove,
  137. };
  138. static int __init tps65911_comparator_init(void)
  139. {
  140. return platform_driver_register(&tps65911_comparator_driver);
  141. }
  142. subsys_initcall(tps65911_comparator_init);
  143. static void __exit tps65911_comparator_exit(void)
  144. {
  145. platform_driver_unregister(&tps65911_comparator_driver);
  146. }
  147. module_exit(tps65911_comparator_exit);
  148. MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
  149. MODULE_DESCRIPTION("TPS65911 comparator driver");
  150. MODULE_LICENSE("GPL v2");
  151. MODULE_ALIAS("platform:tps65911-comparator");