radeon_backlight.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. static struct backlight_properties radeon_bl_data;
  19. struct radeon_bl_privdata {
  20. struct radeonfb_info *rinfo;
  21. uint8_t negative;
  22. };
  23. static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
  24. int level)
  25. {
  26. struct fb_info *info = pdata->rinfo->info;
  27. int rlevel;
  28. mutex_lock(&info->bl_mutex);
  29. /* Get and convert the value */
  30. rlevel = pdata->rinfo->info->bl_curve[level] *
  31. FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
  32. mutex_unlock(&info->bl_mutex);
  33. if (rlevel < 0)
  34. rlevel = 0;
  35. else if (rlevel > MAX_RADEON_LEVEL)
  36. rlevel = MAX_RADEON_LEVEL;
  37. if (pdata->negative)
  38. rlevel = MAX_RADEON_LEVEL - rlevel;
  39. return rlevel;
  40. }
  41. static int radeon_bl_update_status(struct backlight_device *bd)
  42. {
  43. struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
  44. struct radeonfb_info *rinfo = pdata->rinfo;
  45. u32 lvds_gen_cntl, tmpPixclksCntl;
  46. int level;
  47. if (rinfo->mon1_type != MT_LCD)
  48. return 0;
  49. /* We turn off the LCD completely instead of just dimming the
  50. * backlight. This provides some greater power saving and the display
  51. * is useless without backlight anyway.
  52. */
  53. if (bd->props->power != FB_BLANK_UNBLANK ||
  54. bd->props->fb_blank != FB_BLANK_UNBLANK)
  55. level = 0;
  56. else
  57. level = bd->props->brightness;
  58. del_timer_sync(&rinfo->lvds_timer);
  59. radeon_engine_idle();
  60. lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
  61. if (level > 0) {
  62. lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
  63. if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
  64. lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
  65. lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
  66. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  67. lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
  68. lvds_gen_cntl |=
  69. (radeon_bl_get_level_brightness(pdata, level) <<
  70. LVDS_BL_MOD_LEVEL_SHIFT);
  71. lvds_gen_cntl |= LVDS_ON;
  72. lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
  73. rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
  74. mod_timer(&rinfo->lvds_timer,
  75. jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
  76. } else {
  77. lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
  78. lvds_gen_cntl |=
  79. (radeon_bl_get_level_brightness(pdata, level) <<
  80. LVDS_BL_MOD_LEVEL_SHIFT);
  81. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  82. }
  83. rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
  84. rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
  85. & LVDS_STATE_MASK;
  86. } else {
  87. /* Asic bug, when turning off LVDS_ON, we have to make sure
  88. RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
  89. */
  90. tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
  91. if (rinfo->is_mobility || rinfo->is_IGP)
  92. OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
  93. lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
  94. lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
  95. LVDS_BL_MOD_LEVEL_SHIFT);
  96. lvds_gen_cntl |= LVDS_DISPLAY_DIS;
  97. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  98. udelay(100);
  99. lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
  100. OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
  101. lvds_gen_cntl &= ~(LVDS_DIGON);
  102. rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
  103. mod_timer(&rinfo->lvds_timer,
  104. jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
  105. if (rinfo->is_mobility || rinfo->is_IGP)
  106. OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
  107. }
  108. rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
  109. rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
  110. return 0;
  111. }
  112. static int radeon_bl_get_brightness(struct backlight_device *bd)
  113. {
  114. return bd->props->brightness;
  115. }
  116. static struct backlight_properties radeon_bl_data = {
  117. .get_brightness = radeon_bl_get_brightness,
  118. .update_status = radeon_bl_update_status,
  119. .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
  120. };
  121. void radeonfb_bl_init(struct radeonfb_info *rinfo)
  122. {
  123. struct backlight_device *bd;
  124. struct radeon_bl_privdata *pdata;
  125. char name[12];
  126. if (rinfo->mon1_type != MT_LCD)
  127. return;
  128. #ifdef CONFIG_PMAC_BACKLIGHT
  129. if (!pmac_has_backlight_type("ati") &&
  130. !pmac_has_backlight_type("mnca"))
  131. return;
  132. #endif
  133. pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
  134. if (!pdata) {
  135. printk("radeonfb: Memory allocation failed\n");
  136. goto error;
  137. }
  138. snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
  139. bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
  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. machine_is_compatible("PowerBook4,3") ||
  157. machine_is_compatible("PowerBook6,3") ||
  158. machine_is_compatible("PowerBook6,5");
  159. #endif
  160. mutex_lock(&rinfo->info->bl_mutex);
  161. rinfo->info->bl_dev = bd;
  162. fb_bl_default_curve(rinfo->info, 0,
  163. 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
  164. 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
  165. mutex_unlock(&rinfo->info->bl_mutex);
  166. bd->props->brightness = radeon_bl_data.max_brightness;
  167. bd->props->power = FB_BLANK_UNBLANK;
  168. backlight_update_status(bd);
  169. #ifdef CONFIG_PMAC_BACKLIGHT
  170. mutex_lock(&pmac_backlight_mutex);
  171. if (!pmac_backlight)
  172. pmac_backlight = bd;
  173. mutex_unlock(&pmac_backlight_mutex);
  174. #endif
  175. printk("radeonfb: Backlight initialized (%s)\n", name);
  176. return;
  177. error:
  178. kfree(pdata);
  179. return;
  180. }
  181. void radeonfb_bl_exit(struct radeonfb_info *rinfo)
  182. {
  183. #ifdef CONFIG_PMAC_BACKLIGHT
  184. mutex_lock(&pmac_backlight_mutex);
  185. #endif
  186. mutex_lock(&rinfo->info->bl_mutex);
  187. if (rinfo->info->bl_dev) {
  188. struct radeon_bl_privdata *pdata;
  189. #ifdef CONFIG_PMAC_BACKLIGHT
  190. if (pmac_backlight == rinfo->info->bl_dev)
  191. pmac_backlight = NULL;
  192. #endif
  193. pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
  194. backlight_device_unregister(rinfo->info->bl_dev);
  195. kfree(pdata);
  196. rinfo->info->bl_dev = NULL;
  197. printk("radeonfb: Backlight unloaded\n");
  198. }
  199. mutex_unlock(&rinfo->info->bl_mutex);
  200. #ifdef CONFIG_PMAC_BACKLIGHT
  201. mutex_unlock(&pmac_backlight_mutex);
  202. #endif
  203. }