max8925_bl.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Backlight driver for Maxim MAX8925
  4. *
  5. * Copyright (C) 2009 Marvell International Ltd.
  6. * Haojian Zhuang <haojian.zhuang@marvell.com>
  7. */
  8. #include <linux/init.h>
  9. #include <linux/kernel.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/fb.h>
  12. #include <linux/i2c.h>
  13. #include <linux/backlight.h>
  14. #include <linux/mfd/max8925.h>
  15. #include <linux/slab.h>
  16. #include <linux/module.h>
  17. #define MAX_BRIGHTNESS (0xff)
  18. #define MIN_BRIGHTNESS (0)
  19. #define LWX_FREQ(x) (((x - 601) / 100) & 0x7)
  20. struct max8925_backlight_data {
  21. struct max8925_chip *chip;
  22. int current_brightness;
  23. int reg_mode_cntl;
  24. int reg_cntl;
  25. };
  26. static int max8925_backlight_set(struct backlight_device *bl, int brightness)
  27. {
  28. struct max8925_backlight_data *data = bl_get_data(bl);
  29. struct max8925_chip *chip = data->chip;
  30. unsigned char value;
  31. int ret;
  32. if (brightness > MAX_BRIGHTNESS)
  33. value = MAX_BRIGHTNESS;
  34. else
  35. value = brightness;
  36. ret = max8925_reg_write(chip->i2c, data->reg_cntl, value);
  37. if (ret < 0)
  38. goto out;
  39. if (!data->current_brightness && brightness)
  40. /* enable WLED output */
  41. ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1);
  42. else if (!brightness)
  43. /* disable WLED output */
  44. ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0);
  45. if (ret < 0)
  46. goto out;
  47. dev_dbg(chip->dev, "set brightness %d\n", value);
  48. data->current_brightness = value;
  49. return 0;
  50. out:
  51. dev_dbg(chip->dev, "set brightness %d failure with return value:%d\n",
  52. value, ret);
  53. return ret;
  54. }
  55. static int max8925_backlight_update_status(struct backlight_device *bl)
  56. {
  57. return max8925_backlight_set(bl, backlight_get_brightness(bl));
  58. }
  59. static int max8925_backlight_get_brightness(struct backlight_device *bl)
  60. {
  61. struct max8925_backlight_data *data = bl_get_data(bl);
  62. struct max8925_chip *chip = data->chip;
  63. int ret;
  64. ret = max8925_reg_read(chip->i2c, data->reg_cntl);
  65. if (ret < 0)
  66. return -EINVAL;
  67. data->current_brightness = ret;
  68. dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness);
  69. return ret;
  70. }
  71. static const struct backlight_ops max8925_backlight_ops = {
  72. .options = BL_CORE_SUSPENDRESUME,
  73. .update_status = max8925_backlight_update_status,
  74. .get_brightness = max8925_backlight_get_brightness,
  75. };
  76. static void max8925_backlight_dt_init(struct platform_device *pdev)
  77. {
  78. struct device_node *nproot = pdev->dev.parent->of_node, *np;
  79. struct max8925_backlight_pdata *pdata;
  80. u32 val;
  81. if (!nproot || !IS_ENABLED(CONFIG_OF))
  82. return;
  83. pdata = devm_kzalloc(&pdev->dev,
  84. sizeof(struct max8925_backlight_pdata),
  85. GFP_KERNEL);
  86. if (!pdata)
  87. return;
  88. np = of_get_child_by_name(nproot, "backlight");
  89. if (!np) {
  90. dev_err(&pdev->dev, "failed to find backlight node\n");
  91. return;
  92. }
  93. if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
  94. pdata->dual_string = val;
  95. of_node_put(np);
  96. pdev->dev.platform_data = pdata;
  97. }
  98. static int max8925_backlight_probe(struct platform_device *pdev)
  99. {
  100. struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
  101. struct max8925_backlight_pdata *pdata;
  102. struct max8925_backlight_data *data;
  103. struct backlight_device *bl;
  104. struct backlight_properties props;
  105. struct resource *res;
  106. unsigned char value;
  107. int ret = 0;
  108. data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data),
  109. GFP_KERNEL);
  110. if (data == NULL)
  111. return -ENOMEM;
  112. res = platform_get_resource(pdev, IORESOURCE_REG, 0);
  113. if (!res) {
  114. dev_err(&pdev->dev, "No REG resource for mode control!\n");
  115. return -ENXIO;
  116. }
  117. data->reg_mode_cntl = res->start;
  118. res = platform_get_resource(pdev, IORESOURCE_REG, 1);
  119. if (!res) {
  120. dev_err(&pdev->dev, "No REG resource for control!\n");
  121. return -ENXIO;
  122. }
  123. data->reg_cntl = res->start;
  124. data->chip = chip;
  125. data->current_brightness = 0;
  126. memset(&props, 0, sizeof(struct backlight_properties));
  127. props.type = BACKLIGHT_RAW;
  128. props.max_brightness = MAX_BRIGHTNESS;
  129. bl = devm_backlight_device_register(&pdev->dev, "max8925-backlight",
  130. &pdev->dev, data,
  131. &max8925_backlight_ops, &props);
  132. if (IS_ERR(bl)) {
  133. dev_err(&pdev->dev, "failed to register backlight\n");
  134. return PTR_ERR(bl);
  135. }
  136. bl->props.brightness = MAX_BRIGHTNESS;
  137. platform_set_drvdata(pdev, bl);
  138. value = 0;
  139. if (!pdev->dev.platform_data)
  140. max8925_backlight_dt_init(pdev);
  141. pdata = pdev->dev.platform_data;
  142. if (pdata) {
  143. if (pdata->lxw_scl)
  144. value |= (1 << 7);
  145. if (pdata->lxw_freq)
  146. value |= (LWX_FREQ(pdata->lxw_freq) << 4);
  147. if (pdata->dual_string)
  148. value |= (1 << 1);
  149. }
  150. ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value);
  151. if (ret < 0)
  152. return ret;
  153. backlight_update_status(bl);
  154. return 0;
  155. }
  156. static struct platform_driver max8925_backlight_driver = {
  157. .driver = {
  158. .name = "max8925-backlight",
  159. },
  160. .probe = max8925_backlight_probe,
  161. };
  162. module_platform_driver(max8925_backlight_driver);
  163. MODULE_DESCRIPTION("Backlight Driver for Maxim MAX8925");
  164. MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
  165. MODULE_LICENSE("GPL");
  166. MODULE_ALIAS("platform:max8925-backlight");