radeon_backlight.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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_properties props;
  120. struct backlight_device *bd;
  121. struct radeon_bl_privdata *pdata;
  122. char name[12];
  123. if (rinfo->mon1_type != MT_LCD)
  124. return;
  125. #ifdef CONFIG_PMAC_BACKLIGHT
  126. if (!pmac_has_backlight_type("ati") &&
  127. !pmac_has_backlight_type("mnca"))
  128. return;
  129. #endif
  130. pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
  131. if (!pdata) {
  132. printk("radeonfb: Memory allocation failed\n");
  133. goto error;
  134. }
  135. snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
  136. memset(&props, 0, sizeof(struct backlight_properties));
  137. props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
  138. bd = backlight_device_register(name, rinfo->info->dev, pdata,
  139. &radeon_bl_data, &props);
  140. if (IS_ERR(bd)) {
  141. rinfo->info->bl_dev = NULL;
  142. printk("radeonfb: Backlight registration failed\n");
  143. goto error;
  144. }
  145. pdata->rinfo = rinfo;
  146. /* Pardon me for that hack... maybe some day we can figure out in what
  147. * direction backlight should work on a given panel?
  148. */
  149. pdata->negative =
  150. (rinfo->family != CHIP_FAMILY_RV200 &&
  151. rinfo->family != CHIP_FAMILY_RV250 &&
  152. rinfo->family != CHIP_FAMILY_RV280 &&
  153. rinfo->family != CHIP_FAMILY_RV350);
  154. #ifdef CONFIG_PMAC_BACKLIGHT
  155. pdata->negative = pdata->negative ||
  156. of_machine_is_compatible("PowerBook4,3") ||
  157. of_machine_is_compatible("PowerBook6,3") ||
  158. of_machine_is_compatible("PowerBook6,5");
  159. #endif
  160. rinfo->info->bl_dev = bd;
  161. fb_bl_default_curve(rinfo->info, 0,
  162. 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
  163. 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
  164. bd->props.brightness = bd->props.max_brightness;
  165. bd->props.power = FB_BLANK_UNBLANK;
  166. backlight_update_status(bd);
  167. printk("radeonfb: Backlight initialized (%s)\n", name);
  168. return;
  169. error:
  170. kfree(pdata);
  171. return;
  172. }
  173. void radeonfb_bl_exit(struct radeonfb_info *rinfo)
  174. {
  175. struct backlight_device *bd = rinfo->info->bl_dev;
  176. if (bd) {
  177. struct radeon_bl_privdata *pdata;
  178. pdata = bl_get_data(bd);
  179. backlight_device_unregister(bd);
  180. kfree(pdata);
  181. rinfo->info->bl_dev = NULL;
  182. printk("radeonfb: Backlight unloaded\n");
  183. }
  184. }