radeon_backlight.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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. .owner = THIS_MODULE,
  118. .get_brightness = radeon_bl_get_brightness,
  119. .update_status = radeon_bl_update_status,
  120. .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
  121. };
  122. void radeonfb_bl_init(struct radeonfb_info *rinfo)
  123. {
  124. struct backlight_device *bd;
  125. struct radeon_bl_privdata *pdata;
  126. char name[12];
  127. if (rinfo->mon1_type != MT_LCD)
  128. return;
  129. #ifdef CONFIG_PMAC_BACKLIGHT
  130. if (!pmac_has_backlight_type("ati") &&
  131. !pmac_has_backlight_type("mnca"))
  132. return;
  133. #endif
  134. pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
  135. if (!pdata) {
  136. printk("radeonfb: Memory allocation failed\n");
  137. goto error;
  138. }
  139. snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
  140. bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
  141. if (IS_ERR(bd)) {
  142. rinfo->info->bl_dev = NULL;
  143. printk("radeonfb: Backlight registration failed\n");
  144. goto error;
  145. }
  146. pdata->rinfo = rinfo;
  147. /* Pardon me for that hack... maybe some day we can figure out in what
  148. * direction backlight should work on a given panel?
  149. */
  150. pdata->negative =
  151. (rinfo->family != CHIP_FAMILY_RV200 &&
  152. rinfo->family != CHIP_FAMILY_RV250 &&
  153. rinfo->family != CHIP_FAMILY_RV280 &&
  154. rinfo->family != CHIP_FAMILY_RV350);
  155. #ifdef CONFIG_PMAC_BACKLIGHT
  156. pdata->negative = pdata->negative ||
  157. machine_is_compatible("PowerBook4,3") ||
  158. machine_is_compatible("PowerBook6,3") ||
  159. machine_is_compatible("PowerBook6,5");
  160. #endif
  161. mutex_lock(&rinfo->info->bl_mutex);
  162. rinfo->info->bl_dev = bd;
  163. fb_bl_default_curve(rinfo->info, 0,
  164. 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
  165. 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
  166. mutex_unlock(&rinfo->info->bl_mutex);
  167. down(&bd->sem);
  168. bd->props->brightness = radeon_bl_data.max_brightness;
  169. bd->props->power = FB_BLANK_UNBLANK;
  170. bd->props->update_status(bd);
  171. up(&bd->sem);
  172. #ifdef CONFIG_PMAC_BACKLIGHT
  173. mutex_lock(&pmac_backlight_mutex);
  174. if (!pmac_backlight)
  175. pmac_backlight = bd;
  176. mutex_unlock(&pmac_backlight_mutex);
  177. #endif
  178. printk("radeonfb: Backlight initialized (%s)\n", name);
  179. return;
  180. error:
  181. kfree(pdata);
  182. return;
  183. }
  184. void radeonfb_bl_exit(struct radeonfb_info *rinfo)
  185. {
  186. #ifdef CONFIG_PMAC_BACKLIGHT
  187. mutex_lock(&pmac_backlight_mutex);
  188. #endif
  189. mutex_lock(&rinfo->info->bl_mutex);
  190. if (rinfo->info->bl_dev) {
  191. struct radeon_bl_privdata *pdata;
  192. #ifdef CONFIG_PMAC_BACKLIGHT
  193. if (pmac_backlight == rinfo->info->bl_dev)
  194. pmac_backlight = NULL;
  195. #endif
  196. pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
  197. backlight_device_unregister(rinfo->info->bl_dev);
  198. kfree(pdata);
  199. rinfo->info->bl_dev = NULL;
  200. printk("radeonfb: Backlight unloaded\n");
  201. }
  202. mutex_unlock(&rinfo->info->bl_mutex);
  203. #ifdef CONFIG_PMAC_BACKLIGHT
  204. mutex_unlock(&pmac_backlight_mutex);
  205. #endif
  206. }