1 /* 2 * Miscellaneous procedures for dealing with the PowerMac hardware. 3 * Contains support for the backlight. 4 * 5 * Copyright (C) 2000 Benjamin Herrenschmidt 6 * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> 7 * 8 */ 9 10 #include <linux/config.h> 11 #include <linux/kernel.h> 12 #include <linux/fb.h> 13 #include <linux/backlight.h> 14 #include <asm/prom.h> 15 #include <asm/backlight.h> 16 17 #define OLD_BACKLIGHT_MAX 15 18 19 /* Protect the pmac_backlight variable */ 20 DEFINE_MUTEX(pmac_backlight_mutex); 21 22 /* Main backlight storage 23 * 24 * Backlight drivers in this variable are required to have the "props" 25 * attribute set and to have an update_status function. 26 * 27 * We can only store one backlight here, but since Apple laptops have only one 28 * internal display, it doesn't matter. Other backlight drivers can be used 29 * independently. 30 * 31 * Lock ordering: 32 * pmac_backlight_mutex (global, main backlight) 33 * pmac_backlight->sem (backlight class) 34 */ 35 struct backlight_device *pmac_backlight; 36 37 int pmac_has_backlight_type(const char *type) 38 { 39 struct device_node* bk_node = find_devices("backlight"); 40 41 if (bk_node) { 42 char *prop = get_property(bk_node, "backlight-control", NULL); 43 if (prop && strncmp(prop, type, strlen(type)) == 0) 44 return 1; 45 } 46 47 return 0; 48 } 49 50 int pmac_backlight_curve_lookup(struct fb_info *info, int value) 51 { 52 int level = (FB_BACKLIGHT_LEVELS - 1); 53 54 if (info && info->bl_dev) { 55 int i, max = 0; 56 57 /* Look for biggest value */ 58 for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) 59 max = max((int)info->bl_curve[i], max); 60 61 /* Look for nearest value */ 62 for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) { 63 int diff = abs(info->bl_curve[i] - value); 64 if (diff < max) { 65 max = diff; 66 level = i; 67 } 68 } 69 70 } 71 72 return level; 73 } 74 75 static void pmac_backlight_key(int direction) 76 { 77 mutex_lock(&pmac_backlight_mutex); 78 if (pmac_backlight) { 79 struct backlight_properties *props; 80 int brightness; 81 82 down(&pmac_backlight->sem); 83 props = pmac_backlight->props; 84 85 brightness = props->brightness + 86 ((direction?-1:1) * (props->max_brightness / 15)); 87 88 if (brightness < 0) 89 brightness = 0; 90 else if (brightness > props->max_brightness) 91 brightness = props->max_brightness; 92 93 props->brightness = brightness; 94 props->update_status(pmac_backlight); 95 96 up(&pmac_backlight->sem); 97 } 98 mutex_unlock(&pmac_backlight_mutex); 99 } 100 101 void pmac_backlight_key_up() 102 { 103 pmac_backlight_key(0); 104 } 105 106 void pmac_backlight_key_down() 107 { 108 pmac_backlight_key(1); 109 } 110 111 int pmac_backlight_set_legacy_brightness(int brightness) 112 { 113 int error = -ENXIO; 114 115 mutex_lock(&pmac_backlight_mutex); 116 if (pmac_backlight) { 117 struct backlight_properties *props; 118 119 down(&pmac_backlight->sem); 120 props = pmac_backlight->props; 121 props->brightness = brightness * 122 (props->max_brightness + 1) / 123 (OLD_BACKLIGHT_MAX + 1); 124 125 if (props->brightness > props->max_brightness) 126 props->brightness = props->max_brightness; 127 else if (props->brightness < 0) 128 props->brightness = 0; 129 130 props->update_status(pmac_backlight); 131 up(&pmac_backlight->sem); 132 133 error = 0; 134 } 135 mutex_unlock(&pmac_backlight_mutex); 136 137 return error; 138 } 139 140 int pmac_backlight_get_legacy_brightness() 141 { 142 int result = -ENXIO; 143 144 mutex_lock(&pmac_backlight_mutex); 145 if (pmac_backlight) { 146 struct backlight_properties *props; 147 148 down(&pmac_backlight->sem); 149 props = pmac_backlight->props; 150 151 result = props->brightness * 152 (OLD_BACKLIGHT_MAX + 1) / 153 (props->max_brightness + 1); 154 155 up(&pmac_backlight->sem); 156 } 157 mutex_unlock(&pmac_backlight_mutex); 158 159 return result; 160 } 161