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