2 * Miscellaneous procedures for dealing with the PowerMac hardware.
3 * Contains support for the backlight.
5 * Copyright (C) 2000 Benjamin Herrenschmidt
6 * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
10 #include <linux/kernel.h>
12 #include <linux/backlight.h>
14 #include <asm/backlight.h>
16 #define OLD_BACKLIGHT_MAX 15
18 static void pmac_backlight_key_worker(void *data
);
19 static DECLARE_WORK(pmac_backlight_key_work
, pmac_backlight_key_worker
, NULL
);
21 /* Although this variable is used in interrupt context, it makes no sense to
22 * protect it. No user is able to produce enough key events per second and
23 * notice the errors that might happen.
25 static int pmac_backlight_key_queued
;
27 /* Protect the pmac_backlight variable */
28 DEFINE_MUTEX(pmac_backlight_mutex
);
30 /* Main backlight storage
32 * Backlight drivers in this variable are required to have the "props"
33 * attribute set and to have an update_status function.
35 * We can only store one backlight here, but since Apple laptops have only one
36 * internal display, it doesn't matter. Other backlight drivers can be used
40 * pmac_backlight_mutex (global, main backlight)
41 * pmac_backlight->sem (backlight class)
43 struct backlight_device
*pmac_backlight
;
45 int pmac_has_backlight_type(const char *type
)
47 struct device_node
* bk_node
= find_devices("backlight");
50 char *prop
= get_property(bk_node
, "backlight-control", NULL
);
51 if (prop
&& strncmp(prop
, type
, strlen(type
)) == 0)
58 int pmac_backlight_curve_lookup(struct fb_info
*info
, int value
)
60 int level
= (FB_BACKLIGHT_LEVELS
- 1);
62 if (info
&& info
->bl_dev
) {
65 /* Look for biggest value */
66 for (i
= 0; i
< FB_BACKLIGHT_LEVELS
; i
++)
67 max
= max((int)info
->bl_curve
[i
], max
);
69 /* Look for nearest value */
70 for (i
= 0; i
< FB_BACKLIGHT_LEVELS
; i
++) {
71 int diff
= abs(info
->bl_curve
[i
] - value
);
83 static void pmac_backlight_key_worker(void *data
)
85 mutex_lock(&pmac_backlight_mutex
);
87 struct backlight_properties
*props
;
90 down(&pmac_backlight
->sem
);
91 props
= pmac_backlight
->props
;
93 brightness
= props
->brightness
+
94 ((pmac_backlight_key_queued
?-1:1) *
95 (props
->max_brightness
/ 15));
99 else if (brightness
> props
->max_brightness
)
100 brightness
= props
->max_brightness
;
102 props
->brightness
= brightness
;
103 props
->update_status(pmac_backlight
);
105 up(&pmac_backlight
->sem
);
107 mutex_unlock(&pmac_backlight_mutex
);
110 void pmac_backlight_key(int direction
)
112 /* we can receive multiple interrupts here, but the scheduled work
113 * will run only once, with the last value
115 pmac_backlight_key_queued
= direction
;
116 schedule_work(&pmac_backlight_key_work
);
119 int pmac_backlight_set_legacy_brightness(int brightness
)
123 mutex_lock(&pmac_backlight_mutex
);
124 if (pmac_backlight
) {
125 struct backlight_properties
*props
;
127 down(&pmac_backlight
->sem
);
128 props
= pmac_backlight
->props
;
129 props
->brightness
= brightness
*
130 (props
->max_brightness
+ 1) /
131 (OLD_BACKLIGHT_MAX
+ 1);
133 if (props
->brightness
> props
->max_brightness
)
134 props
->brightness
= props
->max_brightness
;
135 else if (props
->brightness
< 0)
136 props
->brightness
= 0;
138 props
->update_status(pmac_backlight
);
139 up(&pmac_backlight
->sem
);
143 mutex_unlock(&pmac_backlight_mutex
);
148 int pmac_backlight_get_legacy_brightness()
152 mutex_lock(&pmac_backlight_mutex
);
153 if (pmac_backlight
) {
154 struct backlight_properties
*props
;
156 down(&pmac_backlight
->sem
);
157 props
= pmac_backlight
->props
;
159 result
= props
->brightness
*
160 (OLD_BACKLIGHT_MAX
+ 1) /
161 (props
->max_brightness
+ 1);
163 up(&pmac_backlight
->sem
);
165 mutex_unlock(&pmac_backlight_mutex
);
170 EXPORT_SYMBOL_GPL(pmac_backlight
);
171 EXPORT_SYMBOL_GPL(pmac_backlight_mutex
);
172 EXPORT_SYMBOL_GPL(pmac_has_backlight_type
);