tps65911-comparator.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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 COMP 0
  24. #define COMP1 1
  25. #define COMP2 2
  26. /* Comparator 1 voltage selection table in millivolts */
  27. static const u16 COMP_VSEL_TABLE[] = {
  28. 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
  29. 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
  30. 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450,
  31. 3500,
  32. };
  33. struct comparator {
  34. const char *name;
  35. int reg;
  36. int uV_max;
  37. const u16 *vsel_table;
  38. };
  39. static struct comparator tps_comparators[] = {
  40. {
  41. .name = "COMP1",
  42. .reg = TPS65911_VMBCH,
  43. .uV_max = 3500,
  44. .vsel_table = COMP_VSEL_TABLE,
  45. },
  46. {
  47. .name = "COMP2",
  48. .reg = TPS65911_VMBCH2,
  49. .uV_max = 3500,
  50. .vsel_table = COMP_VSEL_TABLE,
  51. },
  52. };
  53. static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage)
  54. {
  55. struct comparator tps_comp = tps_comparators[id];
  56. int curr_voltage = 0;
  57. int ret;
  58. u8 index = 0, val;
  59. if (id == COMP)
  60. return 0;
  61. while (curr_voltage < tps_comp.uV_max) {
  62. curr_voltage = tps_comp.vsel_table[index];
  63. if (curr_voltage >= voltage)
  64. break;
  65. else if (curr_voltage < voltage)
  66. index ++;
  67. }
  68. if (curr_voltage > tps_comp.uV_max)
  69. return -EINVAL;
  70. val = index << 1;
  71. ret = tps65910->write(tps65910, tps_comp.reg, 1, &val);
  72. return ret;
  73. }
  74. static int comp_threshold_get(struct tps65910 *tps65910, int id)
  75. {
  76. struct comparator tps_comp = tps_comparators[id];
  77. int ret;
  78. u8 val;
  79. if (id == COMP)
  80. return 0;
  81. ret = tps65910->read(tps65910, tps_comp.reg, 1, &val);
  82. if (ret < 0)
  83. return ret;
  84. val >>= 1;
  85. return tps_comp.vsel_table[val];
  86. }
  87. static ssize_t comp_threshold_show(struct device *dev,
  88. struct device_attribute *attr, char *buf)
  89. {
  90. struct tps65910 *tps65910 = dev_get_drvdata(dev->parent);
  91. struct attribute comp_attr = attr->attr;
  92. int id, uVolt;
  93. if (!strcmp(comp_attr.name, "comp1_threshold"))
  94. id = COMP1;
  95. else if (!strcmp(comp_attr.name, "comp2_threshold"))
  96. id = COMP2;
  97. else
  98. return -EINVAL;
  99. uVolt = comp_threshold_get(tps65910, id);
  100. return sprintf(buf, "%d\n", uVolt);
  101. }
  102. static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL);
  103. static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);
  104. static int tps65911_comparator_probe(struct platform_device *pdev)
  105. {
  106. struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
  107. struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
  108. int ret;
  109. ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold);
  110. if (ret < 0) {
  111. dev_err(&pdev->dev, "cannot set COMP1 threshold\n");
  112. return ret;
  113. }
  114. ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold);
  115. if (ret < 0) {
  116. dev_err(&pdev->dev, "cannot set COMP2 threshold\n");
  117. return ret;
  118. }
  119. /* Create sysfs entry */
  120. ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold);
  121. if (ret < 0)
  122. dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n");
  123. ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold);
  124. if (ret < 0)
  125. dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n");
  126. return ret;
  127. }
  128. static int tps65911_comparator_remove(struct platform_device *pdev)
  129. {
  130. struct tps65910 *tps65910;
  131. tps65910 = dev_get_drvdata(pdev->dev.parent);
  132. device_remove_file(&pdev->dev, &dev_attr_comp2_threshold);
  133. device_remove_file(&pdev->dev, &dev_attr_comp1_threshold);
  134. return 0;
  135. }
  136. static struct platform_driver tps65911_comparator_driver = {
  137. .driver = {
  138. .name = "tps65911-comparator",
  139. },
  140. .probe = tps65911_comparator_probe,
  141. .remove = tps65911_comparator_remove,
  142. };
  143. static int __init tps65911_comparator_init(void)
  144. {
  145. return platform_driver_register(&tps65911_comparator_driver);
  146. }
  147. subsys_initcall(tps65911_comparator_init);
  148. static void __exit tps65911_comparator_exit(void)
  149. {
  150. platform_driver_unregister(&tps65911_comparator_driver);
  151. }
  152. module_exit(tps65911_comparator_exit);
  153. MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
  154. MODULE_DESCRIPTION("TPS65911 comparator driver");
  155. MODULE_LICENSE("GPL v2");
  156. MODULE_ALIAS("platform:tps65911-comparator");