diff options
Diffstat (limited to 'drivers/macintosh/via-pmu-backlight.c')
-rw-r--r-- | drivers/macintosh/via-pmu-backlight.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c new file mode 100644 index 000000000000..b42d05f2aaff --- /dev/null +++ b/drivers/macintosh/via-pmu-backlight.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Backlight code for via-pmu | ||
3 | * | ||
4 | * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. | ||
5 | * Copyright (C) 2001-2002 Benjamin Herrenschmidt | ||
6 | * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <asm/ptrace.h> | ||
11 | #include <linux/adb.h> | ||
12 | #include <linux/pmu.h> | ||
13 | #include <asm/backlight.h> | ||
14 | #include <asm/prom.h> | ||
15 | |||
16 | #define MAX_PMU_LEVEL 0xFF | ||
17 | |||
18 | static struct device_node *vias; | ||
19 | static struct backlight_properties pmu_backlight_data; | ||
20 | |||
21 | static int pmu_backlight_get_level_brightness(struct fb_info *info, | ||
22 | int level) | ||
23 | { | ||
24 | int pmulevel; | ||
25 | |||
26 | /* Get and convert the value */ | ||
27 | mutex_lock(&info->bl_mutex); | ||
28 | pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL; | ||
29 | mutex_unlock(&info->bl_mutex); | ||
30 | |||
31 | if (pmulevel < 0) | ||
32 | pmulevel = 0; | ||
33 | else if (pmulevel > MAX_PMU_LEVEL) | ||
34 | pmulevel = MAX_PMU_LEVEL; | ||
35 | |||
36 | return pmulevel; | ||
37 | } | ||
38 | |||
39 | static int pmu_backlight_update_status(struct backlight_device *bd) | ||
40 | { | ||
41 | struct fb_info *info = class_get_devdata(&bd->class_dev); | ||
42 | struct adb_request req; | ||
43 | int pmulevel, level = bd->props->brightness; | ||
44 | |||
45 | if (vias == NULL) | ||
46 | return -ENODEV; | ||
47 | |||
48 | if (bd->props->power != FB_BLANK_UNBLANK || | ||
49 | bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
50 | level = 0; | ||
51 | |||
52 | pmulevel = pmu_backlight_get_level_brightness(info, level); | ||
53 | |||
54 | pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); | ||
55 | pmu_wait_complete(&req); | ||
56 | |||
57 | pmu_request(&req, NULL, 2, PMU_POWER_CTRL, | ||
58 | PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF)); | ||
59 | pmu_wait_complete(&req); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int pmu_backlight_get_brightness(struct backlight_device *bd) | ||
65 | { | ||
66 | return bd->props->brightness; | ||
67 | } | ||
68 | |||
69 | static struct backlight_properties pmu_backlight_data = { | ||
70 | .owner = THIS_MODULE, | ||
71 | .get_brightness = pmu_backlight_get_brightness, | ||
72 | .update_status = pmu_backlight_update_status, | ||
73 | .max_brightness = (FB_BACKLIGHT_LEVELS - 1), | ||
74 | }; | ||
75 | |||
76 | void __init pmu_backlight_init(struct device_node *in_vias) | ||
77 | { | ||
78 | struct backlight_device *bd; | ||
79 | struct fb_info *info; | ||
80 | char name[10]; | ||
81 | int level, autosave; | ||
82 | |||
83 | vias = in_vias; | ||
84 | |||
85 | /* Special case for the old PowerBook since I can't test on it */ | ||
86 | autosave = | ||
87 | machine_is_compatible("AAPL,3400/2400") || | ||
88 | machine_is_compatible("AAPL,3500"); | ||
89 | |||
90 | if (!autosave && | ||
91 | !pmac_has_backlight_type("pmu") && | ||
92 | !machine_is_compatible("AAPL,PowerBook1998") && | ||
93 | !machine_is_compatible("PowerBook1,1")) | ||
94 | return; | ||
95 | |||
96 | /* Actually, this is a hack, but I don't know of a better way | ||
97 | * to get the first framebuffer device. | ||
98 | */ | ||
99 | info = registered_fb[0]; | ||
100 | if (!info) { | ||
101 | printk("pmubl: No framebuffer found\n"); | ||
102 | goto error; | ||
103 | } | ||
104 | |||
105 | snprintf(name, sizeof(name), "pmubl%d", info->node); | ||
106 | |||
107 | bd = backlight_device_register(name, info, &pmu_backlight_data); | ||
108 | if (IS_ERR(bd)) { | ||
109 | printk("pmubl: Backlight registration failed\n"); | ||
110 | goto error; | ||
111 | } | ||
112 | |||
113 | mutex_lock(&info->bl_mutex); | ||
114 | info->bl_dev = bd; | ||
115 | fb_bl_default_curve(info, 0x7F, 0x46, 0x0E); | ||
116 | mutex_unlock(&info->bl_mutex); | ||
117 | |||
118 | level = pmu_backlight_data.max_brightness; | ||
119 | |||
120 | if (autosave) { | ||
121 | /* read autosaved value if available */ | ||
122 | struct adb_request req; | ||
123 | pmu_request(&req, NULL, 2, 0xd9, 0); | ||
124 | pmu_wait_complete(&req); | ||
125 | |||
126 | mutex_lock(&info->bl_mutex); | ||
127 | level = pmac_backlight_curve_lookup(info, | ||
128 | (req.reply[0] >> 4) * | ||
129 | pmu_backlight_data.max_brightness / 15); | ||
130 | mutex_unlock(&info->bl_mutex); | ||
131 | } | ||
132 | |||
133 | up(&bd->sem); | ||
134 | bd->props->brightness = level; | ||
135 | bd->props->power = FB_BLANK_UNBLANK; | ||
136 | bd->props->update_status(bd); | ||
137 | down(&bd->sem); | ||
138 | |||
139 | mutex_lock(&pmac_backlight_mutex); | ||
140 | if (!pmac_backlight) | ||
141 | pmac_backlight = bd; | ||
142 | mutex_unlock(&pmac_backlight_mutex); | ||
143 | |||
144 | printk("pmubl: Backlight initialized (%s)\n", name); | ||
145 | |||
146 | return; | ||
147 | |||
148 | error: | ||
149 | return; | ||
150 | } | ||