xref: /linux/arch/powerpc/platforms/powermac/backlight.c (revision 5e8d780d745c1619aba81fe7166c5a4b5cad2b84)
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