aat2870_bl.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/drivers/video/backlight/aat2870_bl.c
  4. *
  5. * Copyright (c) 2011, NVIDIA Corporation.
  6. * Author: Jin Park <jinyoungp@nvidia.com>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/kernel.h>
  10. #include <linux/init.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/mutex.h>
  13. #include <linux/delay.h>
  14. #include <linux/backlight.h>
  15. #include <linux/mfd/aat2870.h>
  16. struct aat2870_bl_driver_data {
  17. struct platform_device *pdev;
  18. struct backlight_device *bd;
  19. int channels;
  20. int max_current;
  21. int brightness; /* current brightness */
  22. };
  23. static inline int aat2870_brightness(struct aat2870_bl_driver_data *aat2870_bl,
  24. int brightness)
  25. {
  26. struct backlight_device *bd = aat2870_bl->bd;
  27. int val;
  28. val = brightness * (aat2870_bl->max_current - 1);
  29. val /= bd->props.max_brightness;
  30. return val;
  31. }
  32. static inline int aat2870_bl_enable(struct aat2870_bl_driver_data *aat2870_bl)
  33. {
  34. struct aat2870_data *aat2870
  35. = dev_get_drvdata(aat2870_bl->pdev->dev.parent);
  36. return aat2870->write(aat2870, AAT2870_BL_CH_EN,
  37. (u8)aat2870_bl->channels);
  38. }
  39. static inline int aat2870_bl_disable(struct aat2870_bl_driver_data *aat2870_bl)
  40. {
  41. struct aat2870_data *aat2870
  42. = dev_get_drvdata(aat2870_bl->pdev->dev.parent);
  43. return aat2870->write(aat2870, AAT2870_BL_CH_EN, 0x0);
  44. }
  45. static int aat2870_bl_update_status(struct backlight_device *bd)
  46. {
  47. struct aat2870_bl_driver_data *aat2870_bl = bl_get_data(bd);
  48. struct aat2870_data *aat2870 =
  49. dev_get_drvdata(aat2870_bl->pdev->dev.parent);
  50. int brightness = backlight_get_brightness(bd);
  51. int ret;
  52. if ((brightness < 0) || (bd->props.max_brightness < brightness)) {
  53. dev_err(&bd->dev, "invalid brightness, %d\n", brightness);
  54. return -EINVAL;
  55. }
  56. dev_dbg(&bd->dev, "brightness=%d, power=%d, state=%d\n",
  57. bd->props.brightness, bd->props.power, bd->props.state);
  58. ret = aat2870->write(aat2870, AAT2870_BLM,
  59. (u8)aat2870_brightness(aat2870_bl, brightness));
  60. if (ret < 0)
  61. return ret;
  62. if (brightness == 0) {
  63. ret = aat2870_bl_disable(aat2870_bl);
  64. if (ret < 0)
  65. return ret;
  66. } else if (aat2870_bl->brightness == 0) {
  67. ret = aat2870_bl_enable(aat2870_bl);
  68. if (ret < 0)
  69. return ret;
  70. }
  71. aat2870_bl->brightness = brightness;
  72. return 0;
  73. }
  74. static const struct backlight_ops aat2870_bl_ops = {
  75. .options = BL_CORE_SUSPENDRESUME,
  76. .update_status = aat2870_bl_update_status,
  77. };
  78. static int aat2870_bl_probe(struct platform_device *pdev)
  79. {
  80. struct aat2870_bl_platform_data *pdata = dev_get_platdata(&pdev->dev);
  81. struct aat2870_bl_driver_data *aat2870_bl;
  82. struct backlight_device *bd;
  83. struct backlight_properties props;
  84. int ret = 0;
  85. if (!pdata) {
  86. dev_err(&pdev->dev, "No platform data\n");
  87. ret = -ENXIO;
  88. goto out;
  89. }
  90. if (pdev->id != AAT2870_ID_BL) {
  91. dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
  92. ret = -EINVAL;
  93. goto out;
  94. }
  95. aat2870_bl = devm_kzalloc(&pdev->dev,
  96. sizeof(struct aat2870_bl_driver_data),
  97. GFP_KERNEL);
  98. if (!aat2870_bl) {
  99. ret = -ENOMEM;
  100. goto out;
  101. }
  102. memset(&props, 0, sizeof(struct backlight_properties));
  103. props.type = BACKLIGHT_RAW;
  104. bd = devm_backlight_device_register(&pdev->dev, "aat2870-backlight",
  105. &pdev->dev, aat2870_bl, &aat2870_bl_ops,
  106. &props);
  107. if (IS_ERR(bd)) {
  108. dev_err(&pdev->dev,
  109. "Failed allocate memory for backlight device\n");
  110. ret = PTR_ERR(bd);
  111. goto out;
  112. }
  113. aat2870_bl->pdev = pdev;
  114. platform_set_drvdata(pdev, aat2870_bl);
  115. aat2870_bl->bd = bd;
  116. if (pdata->channels > 0)
  117. aat2870_bl->channels = pdata->channels;
  118. else
  119. aat2870_bl->channels = AAT2870_BL_CH_ALL;
  120. if (pdata->max_current > 0)
  121. aat2870_bl->max_current = pdata->max_current;
  122. else
  123. aat2870_bl->max_current = AAT2870_CURRENT_27_9;
  124. if (pdata->max_brightness > 0)
  125. bd->props.max_brightness = pdata->max_brightness;
  126. else
  127. bd->props.max_brightness = 255;
  128. aat2870_bl->brightness = 0;
  129. bd->props.power = BACKLIGHT_POWER_ON;
  130. bd->props.brightness = bd->props.max_brightness;
  131. ret = aat2870_bl_update_status(bd);
  132. if (ret < 0) {
  133. dev_err(&pdev->dev, "Failed to initialize\n");
  134. return ret;
  135. }
  136. return 0;
  137. out:
  138. return ret;
  139. }
  140. static void aat2870_bl_remove(struct platform_device *pdev)
  141. {
  142. struct aat2870_bl_driver_data *aat2870_bl = platform_get_drvdata(pdev);
  143. struct backlight_device *bd = aat2870_bl->bd;
  144. bd->props.power = BACKLIGHT_POWER_OFF;
  145. bd->props.brightness = 0;
  146. backlight_update_status(bd);
  147. }
  148. static struct platform_driver aat2870_bl_driver = {
  149. .driver = {
  150. .name = "aat2870-backlight",
  151. },
  152. .probe = aat2870_bl_probe,
  153. .remove = aat2870_bl_remove,
  154. };
  155. static int __init aat2870_bl_init(void)
  156. {
  157. return platform_driver_register(&aat2870_bl_driver);
  158. }
  159. subsys_initcall(aat2870_bl_init);
  160. static void __exit aat2870_bl_exit(void)
  161. {
  162. platform_driver_unregister(&aat2870_bl_driver);
  163. }
  164. module_exit(aat2870_bl_exit);
  165. MODULE_DESCRIPTION("AnalogicTech AAT2870 Backlight");
  166. MODULE_LICENSE("GPL");
  167. MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");