via-pmu-backlight.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Backlight code for via-pmu
  3. *
  4. * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
  5. * Copyright (C) 2001-2002 Benjamin Herrenschmidt
  6. * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  7. *
  8. */
  9. #include <asm/ptrace.h>
  10. #include <linux/adb.h>
  11. #include <linux/pmu.h>
  12. #include <asm/backlight.h>
  13. #include <asm/prom.h>
  14. #define MAX_PMU_LEVEL 0xFF
  15. static struct device_node *vias;
  16. static struct backlight_properties pmu_backlight_data;
  17. static int pmu_backlight_get_level_brightness(struct fb_info *info,
  18. int level)
  19. {
  20. int pmulevel;
  21. /* Get and convert the value */
  22. mutex_lock(&info->bl_mutex);
  23. pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
  24. mutex_unlock(&info->bl_mutex);
  25. if (pmulevel < 0)
  26. pmulevel = 0;
  27. else if (pmulevel > MAX_PMU_LEVEL)
  28. pmulevel = MAX_PMU_LEVEL;
  29. return pmulevel;
  30. }
  31. static int pmu_backlight_update_status(struct backlight_device *bd)
  32. {
  33. struct fb_info *info = class_get_devdata(&bd->class_dev);
  34. struct adb_request req;
  35. int pmulevel, level = bd->props->brightness;
  36. if (vias == NULL)
  37. return -ENODEV;
  38. if (bd->props->power != FB_BLANK_UNBLANK ||
  39. bd->props->fb_blank != FB_BLANK_UNBLANK)
  40. level = 0;
  41. pmulevel = pmu_backlight_get_level_brightness(info, level);
  42. pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
  43. pmu_wait_complete(&req);
  44. pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
  45. PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
  46. pmu_wait_complete(&req);
  47. return 0;
  48. }
  49. static int pmu_backlight_get_brightness(struct backlight_device *bd)
  50. {
  51. return bd->props->brightness;
  52. }
  53. static struct backlight_properties pmu_backlight_data = {
  54. .owner = THIS_MODULE,
  55. .get_brightness = pmu_backlight_get_brightness,
  56. .update_status = pmu_backlight_update_status,
  57. .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
  58. };
  59. void __init pmu_backlight_init(struct device_node *in_vias)
  60. {
  61. struct backlight_device *bd;
  62. struct fb_info *info;
  63. char name[10];
  64. int level, autosave;
  65. vias = in_vias;
  66. /* Special case for the old PowerBook since I can't test on it */
  67. autosave =
  68. machine_is_compatible("AAPL,3400/2400") ||
  69. machine_is_compatible("AAPL,3500");
  70. if (!autosave &&
  71. !pmac_has_backlight_type("pmu") &&
  72. !machine_is_compatible("AAPL,PowerBook1998") &&
  73. !machine_is_compatible("PowerBook1,1"))
  74. return;
  75. /* Actually, this is a hack, but I don't know of a better way
  76. * to get the first framebuffer device.
  77. */
  78. info = registered_fb[0];
  79. if (!info) {
  80. printk("pmubl: No framebuffer found\n");
  81. goto error;
  82. }
  83. snprintf(name, sizeof(name), "pmubl%d", info->node);
  84. bd = backlight_device_register(name, info, &pmu_backlight_data);
  85. if (IS_ERR(bd)) {
  86. printk("pmubl: Backlight registration failed\n");
  87. goto error;
  88. }
  89. mutex_lock(&info->bl_mutex);
  90. info->bl_dev = bd;
  91. fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
  92. mutex_unlock(&info->bl_mutex);
  93. level = pmu_backlight_data.max_brightness;
  94. if (autosave) {
  95. /* read autosaved value if available */
  96. struct adb_request req;
  97. pmu_request(&req, NULL, 2, 0xd9, 0);
  98. pmu_wait_complete(&req);
  99. mutex_lock(&info->bl_mutex);
  100. level = pmac_backlight_curve_lookup(info,
  101. (req.reply[0] >> 4) *
  102. pmu_backlight_data.max_brightness / 15);
  103. mutex_unlock(&info->bl_mutex);
  104. }
  105. up(&bd->sem);
  106. bd->props->brightness = level;
  107. bd->props->power = FB_BLANK_UNBLANK;
  108. bd->props->update_status(bd);
  109. down(&bd->sem);
  110. mutex_lock(&pmac_backlight_mutex);
  111. if (!pmac_backlight)
  112. pmac_backlight = bd;
  113. mutex_unlock(&pmac_backlight_mutex);
  114. printk("pmubl: Backlight initialized (%s)\n", name);
  115. return;
  116. error:
  117. return;
  118. }