1 /*
2  * Miscellaneous procedures for dealing with the PowerMac hardware.
3  * Contains support for the backlight.
4  *
5  *   Copyright (C) 2000 Benjamin Herrenschmidt
6  *
7  */
8 
9 #include <linux/config.h>
10 #include <linux/kernel.h>
11 #include <linux/stddef.h>
12 #include <linux/reboot.h>
13 #include <linux/nvram.h>
14 #include <asm/sections.h>
15 #include <asm/ptrace.h>
16 #include <asm/io.h>
17 #include <asm/pgtable.h>
18 #include <asm/system.h>
19 #include <asm/prom.h>
20 #include <asm/machdep.h>
21 #include <asm/nvram.h>
22 #include <asm/backlight.h>
23 
24 #include <linux/adb.h>
25 #include <linux/pmu.h>
26 
27 static struct backlight_controller *backlighter = NULL;
28 static void* backlighter_data = NULL;
29 static int backlight_autosave = 0;
30 static int backlight_level = BACKLIGHT_MAX;
31 static int backlight_enabled = 1;
32 
33 void __pmac
register_backlight_controller(struct backlight_controller * ctrler,void * data,char * type)34 register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
35 {
36 	struct device_node* bk_node;
37 	char *prop;
38 	int valid = 0;
39 
40 	bk_node = find_devices("backlight");
41 
42 #ifdef CONFIG_ADB_PMU
43 	/* Special case for the old PowerBook since I can't test on it */
44 	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
45 		|| machine_is_compatible("AAPL,3500");
46 	if ((backlight_autosave
47 	     || machine_is_compatible("AAPL,PowerBook1998")
48 	     || machine_is_compatible("PowerBook1,1"))
49 	    && !strcmp(type, "pmu"))
50 		valid = 1;
51 #endif
52 	if (bk_node) {
53 		prop = get_property(bk_node, "backlight-control", NULL);
54 		if (prop && !strncmp(prop, type, strlen(type)))
55 			valid = 1;
56 	}
57 	if (!valid)
58 		return;
59 	backlighter = ctrler;
60 	backlighter_data = data;
61 
62 	if (bk_node && !backlight_autosave)
63 		prop = get_property(bk_node, "bklt", NULL);
64 	else
65 		prop = NULL;
66 	if (prop) {
67 		backlight_level = ((*prop)+1) >> 1;
68 		if (backlight_level > BACKLIGHT_MAX)
69 			backlight_level = BACKLIGHT_MAX;
70 	}
71 
72 #ifdef CONFIG_ADB_PMU
73 	if (backlight_autosave) {
74 		struct adb_request req;
75 		pmu_request(&req, NULL, 2, 0xd9, 0);
76 		while (!req.complete)
77 			pmu_poll();
78 		backlight_level = req.reply[0] >> 4;
79 	}
80 #endif
81 	if (!backlighter->set_enable(1, backlight_level, data))
82 		backlight_enabled = 1;
83 
84 	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
85 		type, backlight_level);
86 }
87 
88 void __pmac
unregister_backlight_controller(struct backlight_controller * ctrler,void * data)89 unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
90 {
91 	/* We keep the current backlight level (for now) */
92 	if (ctrler == backlighter && data == backlighter_data)
93 		backlighter = NULL;
94 }
95 
96 int __pmac
set_backlight_enable(int enable)97 set_backlight_enable(int enable)
98 {
99 	int rc;
100 
101 	if (!backlighter)
102 		return -ENODEV;
103 	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
104 	if (!rc)
105 		backlight_enabled = enable;
106 	return rc;
107 }
108 
109 int __pmac
get_backlight_enable(void)110 get_backlight_enable(void)
111 {
112 	if (!backlighter)
113 		return -ENODEV;
114 	return backlight_enabled;
115 }
116 
117 int __pmac
set_backlight_level(int level)118 set_backlight_level(int level)
119 {
120 	int rc = 0;
121 
122 	if (!backlighter)
123 		return -ENODEV;
124 	if (level < BACKLIGHT_MIN)
125 		level = BACKLIGHT_OFF;
126 	if (level > BACKLIGHT_MAX)
127 		level = BACKLIGHT_MAX;
128 	if (backlight_enabled)
129 		rc = backlighter->set_level(level, backlighter_data);
130 	if (!rc)
131 		backlight_level = level;
132 	if (!rc && !backlight_autosave) {
133 		level <<=1;
134 		if (level & 0x10)
135 			level |= 0x01;
136 		// -- todo: save to property "bklt"
137 	}
138 	return rc;
139 }
140 
141 int __pmac
get_backlight_level(void)142 get_backlight_level(void)
143 {
144 	if (!backlighter)
145 		return -ENODEV;
146 	return backlight_level;
147 }
148