diff options
author | Mario Schwalbe <schwalbe@inf.tu-dresden.de> | 2009-01-10 19:11:34 -0500 |
---|---|---|
committer | Richard Purdie <rpurdie@linux.intel.com> | 2009-04-06 11:06:55 -0400 |
commit | c78a628849675580c7c5e1f07193c632e4b6827f (patch) | |
tree | cfeb5bf04e1a33b2ebeacabe9a0854cc8b1e2473 /drivers/video/backlight | |
parent | 0221c81b1b8eb0cbb6b30a0ced52ead32d2b4e4c (diff) |
backlight: Add support for MacBook 5, MacBook Air 2, and MacBook Pro 5
This patch adds support for the new Apple models incorporating an Nvidia
chipset. Apple still uses the same protocol as on older models, but the
registers moved to a different address. To do this, two sets of functions
are added for the Intel/Nvidia chipset models and passed by the DMI_MATCH
function.
The initial code has been contributed by Hu Gang <hugang@soulinfo.com>.
The driver is known to work on MacBook Pro 3, MacBook Pro 4 and MacBook
Pro 5.
Its known to work with limitations on MacBook 5 / MacBook Air 2. Changing
brightness within X doesn't work, if using Nvidia's proprietary graphics
driver with no known fix at present. Changing brightness on a text console
or using the open-source driver does work.
MacBook Pro 5 has a known bug where the initial brightness after bootup is
the last recently used brightness (in Mac OSX), while the firmware reports
maximum. Impossible to fix.
[akpm@linux-foundation.org: build fix]
[rpurdie@linux.intel.com: Rebased the patch against latest git]
Signed-off-by: Mario Schwalbe <schwalbe@inf.tu-dresden.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'drivers/video/backlight')
-rw-r--r-- | drivers/video/backlight/mbp_nvidia_bl.c | 162 |
1 files changed, 126 insertions, 36 deletions
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 65864c500455..ce09b83244ac 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c | |||
@@ -27,52 +27,142 @@ | |||
27 | 27 | ||
28 | static struct backlight_device *mbp_backlight_device; | 28 | static struct backlight_device *mbp_backlight_device; |
29 | 29 | ||
30 | static struct dmi_system_id __initdata mbp_device_table[] = { | 30 | /* Structure to be passed to the DMI_MATCH function. */ |
31 | { | 31 | struct dmi_match_data { |
32 | .ident = "3,1", | 32 | /* I/O resource to allocate. */ |
33 | .matches = { | 33 | unsigned long iostart; |
34 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | 34 | unsigned long iolen; |
35 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), | 35 | /* Backlight operations structure. */ |
36 | }, | 36 | struct backlight_ops backlight_ops; |
37 | }, | ||
38 | { | ||
39 | .ident = "3,2", | ||
40 | .matches = { | ||
41 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
42 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"), | ||
43 | }, | ||
44 | }, | ||
45 | { | ||
46 | .ident = "4,1", | ||
47 | .matches = { | ||
48 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
49 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"), | ||
50 | }, | ||
51 | }, | ||
52 | { } | ||
53 | }; | 37 | }; |
54 | 38 | ||
55 | static int mbp_send_intensity(struct backlight_device *bd) | 39 | /* |
40 | * Implementation for MacBooks with Intel chipset. | ||
41 | */ | ||
42 | static int intel_chipset_send_intensity(struct backlight_device *bd) | ||
56 | { | 43 | { |
57 | int intensity = bd->props.brightness; | 44 | int intensity = bd->props.brightness; |
58 | 45 | ||
59 | outb(0x04 | (intensity << 4), 0xb3); | 46 | outb(0x04 | (intensity << 4), 0xb3); |
60 | outb(0xbf, 0xb2); | 47 | outb(0xbf, 0xb2); |
61 | |||
62 | return 0; | 48 | return 0; |
63 | } | 49 | } |
64 | 50 | ||
65 | static int mbp_get_intensity(struct backlight_device *bd) | 51 | static int intel_chipset_get_intensity(struct backlight_device *bd) |
66 | { | 52 | { |
67 | outb(0x03, 0xb3); | 53 | outb(0x03, 0xb3); |
68 | outb(0xbf, 0xb2); | 54 | outb(0xbf, 0xb2); |
69 | return inb(0xb3) >> 4; | 55 | return inb(0xb3) >> 4; |
70 | } | 56 | } |
71 | 57 | ||
72 | static struct backlight_ops mbp_ops = { | 58 | static const struct dmi_match_data intel_chipset_data = { |
73 | .options = BL_CORE_SUSPENDRESUME, | 59 | .iostart = 0xb2, |
74 | .get_brightness = mbp_get_intensity, | 60 | .iolen = 2, |
75 | .update_status = mbp_send_intensity, | 61 | .backlight_ops = { |
62 | .options = BL_CORE_SUSPENDRESUME, | ||
63 | .get_brightness = intel_chipset_get_intensity, | ||
64 | .update_status = intel_chipset_send_intensity, | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * Implementation for MacBooks with Nvidia chipset. | ||
70 | */ | ||
71 | static int nvidia_chipset_send_intensity(struct backlight_device *bd) | ||
72 | { | ||
73 | int intensity = bd->props.brightness; | ||
74 | |||
75 | outb(0x04 | (intensity << 4), 0x52f); | ||
76 | outb(0xbf, 0x52e); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int nvidia_chipset_get_intensity(struct backlight_device *bd) | ||
81 | { | ||
82 | outb(0x03, 0x52f); | ||
83 | outb(0xbf, 0x52e); | ||
84 | return inb(0x52f) >> 4; | ||
85 | } | ||
86 | |||
87 | static const struct dmi_match_data nvidia_chipset_data = { | ||
88 | .iostart = 0x52e, | ||
89 | .iolen = 2, | ||
90 | .backlight_ops = { | ||
91 | .options = BL_CORE_SUSPENDRESUME, | ||
92 | .get_brightness = nvidia_chipset_get_intensity, | ||
93 | .update_status = nvidia_chipset_send_intensity | ||
94 | } | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * DMI matching. | ||
99 | */ | ||
100 | static /* const */ struct dmi_match_data *driver_data; | ||
101 | |||
102 | static int mbp_dmi_match(const struct dmi_system_id *id) | ||
103 | { | ||
104 | driver_data = id->driver_data; | ||
105 | |||
106 | printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident); | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | static const struct dmi_system_id __initdata mbp_device_table[] = { | ||
111 | { | ||
112 | .callback = mbp_dmi_match, | ||
113 | .ident = "MacBookPro 3,1", | ||
114 | .matches = { | ||
115 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
116 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), | ||
117 | }, | ||
118 | .driver_data = (void *)&intel_chipset_data, | ||
119 | }, | ||
120 | { | ||
121 | .callback = mbp_dmi_match, | ||
122 | .ident = "MacBookPro 3,2", | ||
123 | .matches = { | ||
124 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
125 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"), | ||
126 | }, | ||
127 | .driver_data = (void *)&intel_chipset_data, | ||
128 | }, | ||
129 | { | ||
130 | .callback = mbp_dmi_match, | ||
131 | .ident = "MacBookPro 4,1", | ||
132 | .matches = { | ||
133 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
134 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"), | ||
135 | }, | ||
136 | .driver_data = (void *)&intel_chipset_data, | ||
137 | }, | ||
138 | { | ||
139 | .callback = mbp_dmi_match, | ||
140 | .ident = "MacBook 5,1", | ||
141 | .matches = { | ||
142 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
143 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"), | ||
144 | }, | ||
145 | .driver_data = (void *)&nvidia_chipset_data, | ||
146 | }, | ||
147 | { | ||
148 | .callback = mbp_dmi_match, | ||
149 | .ident = "MacBookAir 2,1", | ||
150 | .matches = { | ||
151 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
152 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"), | ||
153 | }, | ||
154 | .driver_data = (void *)&nvidia_chipset_data, | ||
155 | }, | ||
156 | { | ||
157 | .callback = mbp_dmi_match, | ||
158 | .ident = "MacBookPro 5,1", | ||
159 | .matches = { | ||
160 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
161 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), | ||
162 | }, | ||
163 | .driver_data = (void *)&nvidia_chipset_data, | ||
164 | }, | ||
165 | { } | ||
76 | }; | 166 | }; |
77 | 167 | ||
78 | static int __init mbp_init(void) | 168 | static int __init mbp_init(void) |
@@ -80,20 +170,20 @@ static int __init mbp_init(void) | |||
80 | if (!dmi_check_system(mbp_device_table)) | 170 | if (!dmi_check_system(mbp_device_table)) |
81 | return -ENODEV; | 171 | return -ENODEV; |
82 | 172 | ||
83 | if (!request_region(0xb2, 2, "Macbook Pro backlight")) | 173 | if (!request_region(driver_data->iostart, driver_data->iolen, |
174 | "Macbook Pro backlight")) | ||
84 | return -ENXIO; | 175 | return -ENXIO; |
85 | 176 | ||
86 | mbp_backlight_device = backlight_device_register("mbp_backlight", | 177 | mbp_backlight_device = backlight_device_register("mbp_backlight", |
87 | NULL, NULL, | 178 | NULL, NULL, &driver_data->backlight_ops); |
88 | &mbp_ops); | ||
89 | if (IS_ERR(mbp_backlight_device)) { | 179 | if (IS_ERR(mbp_backlight_device)) { |
90 | release_region(0xb2, 2); | 180 | release_region(driver_data->iostart, driver_data->iolen); |
91 | return PTR_ERR(mbp_backlight_device); | 181 | return PTR_ERR(mbp_backlight_device); |
92 | } | 182 | } |
93 | 183 | ||
94 | mbp_backlight_device->props.max_brightness = 15; | 184 | mbp_backlight_device->props.max_brightness = 15; |
95 | mbp_backlight_device->props.brightness = | 185 | mbp_backlight_device->props.brightness = |
96 | mbp_get_intensity(mbp_backlight_device); | 186 | driver_data->backlight_ops.get_brightness(mbp_backlight_device); |
97 | backlight_update_status(mbp_backlight_device); | 187 | backlight_update_status(mbp_backlight_device); |
98 | 188 | ||
99 | return 0; | 189 | return 0; |
@@ -103,7 +193,7 @@ static void __exit mbp_exit(void) | |||
103 | { | 193 | { |
104 | backlight_device_unregister(mbp_backlight_device); | 194 | backlight_device_unregister(mbp_backlight_device); |
105 | 195 | ||
106 | release_region(0xb2, 2); | 196 | release_region(driver_data->iostart, driver_data->iolen); |
107 | } | 197 | } |
108 | 198 | ||
109 | module_init(mbp_init); | 199 | module_init(mbp_init); |