radeon_backlight.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Backlight code for ATI Radeon based graphic cards
  3. *
  4. * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
  5. * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
  6. * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include "radeonfb.h"
  13. #include <linux/backlight.h>
  14. #ifdef CONFIG_PMAC_BACKLIGHT
  15. #include <asm/backlight.h>
  16. #endif
  17. #define MAX_RADEON_LEVEL 0xFF
  18. struct radeon_bl_privdata {
  19. struct radeonfb_info *rinfo;
  20. uint8_t negative;
  21. };
  22. static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
  23. int level)
  24. {
  25. int rlevel;
  26. /* Get and convert the value */
  27. /* No locking of bl_curve since we read a single value */
  28. rlevel = pdata->rinfo->info->bl_curve[level] *
  29. FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
  30. if (rlevel < 0)
  31. rlevel = 0;
  32. else if (rlevel > MAX_RADEON_LEVEL)
  33. rlevel = MAX_RADEON_LEVEL;
  34. if (pdata->negative)
  35. rlevel = MAX_RADEON_LEVEL - rlevel;
  36. return rlevel;
  37. }
  38. static int radeon_bl_update_status(struct backlight_device *bd)
  39. {
  40. struct radeon_bl_privdata *pdata = bl_get_data(bd);
  41. struct radeonfb_info *rinfo = pdata->rinfo;
  42. u32 lvds_gen_cntl, tmpPixclksCntl;
  43. int level;
  44. if (rinfo->mon1_type != MT_LCD)
  45. return 0;
  46. /* We turn off the LCD completely instead of just dimming the
  47. * backlight. This provides some greater power saving and the display
  48. * is useless without backlight anyway.
  49. */
  50. if (bd->props.power != FB_BLANK_UNBLANK ||
  51. bd->props.fb_blank != FB_BLANK_UNBLANK)
  52. level = 0;
  53. else
  54. level = bd->props.brightness;
  55. del_timer_sync(&rinfo->lvds_timer);
  56. radeon_engine_idle();
  57. lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
  58. if (level > 0) {
  59. lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
  60. if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
  61. lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
  62. lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
  63. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  64. lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
  65. lvds_gen_cntl |=
  66. (radeon_bl_get_level_brightness(pdata, level) <<
  67. LVDS_BL_MOD_LEVEL_SHIFT);
  68. lvds_gen_cntl |= LVDS_ON;
  69. lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
  70. rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
  71. mod_timer(&rinfo->lvds_timer,
  72. jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
  73. } else {
  74. lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
  75. lvds_gen_cntl |=
  76. (radeon_bl_get_level_brightness(pdata, level) <<
  77. LVDS_BL_MOD_LEVEL_SHIFT);
  78. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  79. }
  80. rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
  81. rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
  82. & LVDS_STATE_MASK;
  83. } else {
  84. /* Asic bug, when turning off LVDS_ON, we have to make sure
  85. RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
  86. */
  87. tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
  88. if (rinfo->is_mobility || rinfo->is_IGP)
  89. OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
  90. lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
  91. lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
  92. LVDS_BL_MOD_LEVEL_SHIFT);
  93. lvds_gen_cntl |= LVDS_DISPLAY_DIS;
  94. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  95. udelay(100);
  96. lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
  97. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  98. lvds_gen_cntl &= ~(LVDS_DIGON);
  99. rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
  100. mod_timer(&rinfo->lvds_timer,
  101. jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
  102. if (rinfo->is_mobility || rinfo->is_IGP)
  103. OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
  104. }
  105. rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
  106. rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
  107. return 0;
  108. }
  109. static int radeon_bl_get_brightness(struct backlight_device *bd)
  110. {
  111. return bd->props.brightness;
  112. }
  113. static struct backlight_ops radeon_bl_data = {
  114. .get_brightness = radeon_bl_get_brightness,
  115. .update_status = radeon_bl_update_status,
  116. };
  117. void radeonfb_bl_init(struct radeonfb_info *rinfo)
  118. {
  119. struct backlight_device *bd;
  120. struct radeon_bl_privdata *pdata;
  121. char name[12];
  122. if (rinfo->mon1_type != MT_LCD)
  123. return;
  124. #ifdef CONFIG_PMAC_BACKLIGHT
  125. if (!pmac_has_backlight_type("ati") &&
  126. !pmac_has_backlight_type("mnca"))
  127. return;
  128. #endif
  129. pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
  130. if (!pdata) {
  131. printk("radeonfb: Memory allocation failed\n");
  132. goto error;
  133. }
  134. snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
  135. bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
  136. if (IS_ERR(bd)) {
  137. rinfo->info->bl_dev = NULL;
  138. printk("radeonfb: Backlight registration failed\n");
  139. goto error;
  140. }
  141. pdata->rinfo = rinfo;
  142. /* Pardon me for that hack... maybe some day we can figure out in what
  143. * direction backlight should work on a given panel?
  144. */
  145. pdata->negative =
  146. (rinfo->family != CHIP_FAMILY_RV200 &&
  147. rinfo->family != CHIP_FAMILY_RV250 &&
  148. rinfo->family != CHIP_FAMILY_RV280 &&
  149. rinfo->family != CHIP_FAMILY_RV350);
  150. #ifdef CONFIG_PMAC_BACKLIGHT
  151. pdata->negative = pdata->negative ||
  152. machine_is_compatible("PowerBook4,3") ||
  153. machine_is_compatible("PowerBook6,3") ||
  154. machine_is_compatible("PowerBook6,5");
  155. #endif
  156. rinfo->info->bl_dev = bd;
  157. fb_bl_default_curve(rinfo->info, 0,
  158. 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
  159. 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
  160. bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
  161. bd->props.brightness = bd->props.max_brightness;
  162. bd->props.power = FB_BLANK_UNBLANK;
  163. backlight_update_status(bd);
  164. printk("radeonfb: Backlight initialized (%s)\n", name);
  165. return;
  166. error:
  167. kfree(pdata);
  168. return;
  169. }
  170. void radeonfb_bl_exit(struct radeonfb_info *rinfo)
  171. {
  172. struct backlight_device *bd = rinfo->info->bl_dev;
  173. if (bd) {
  174. struct radeon_bl_privdata *pdata;
  175. pdata = bl_get_data(bd);
  176. backlight_device_unregister(bd);
  177. kfree(pdata);
  178. rinfo->info->bl_dev = NULL;
  179. printk("radeonfb: Backlight unloaded\n");
  180. }
  181. }