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>
This commit is contained in:
parent
0221c81b1b
commit
c78a628849
|
@ -27,52 +27,142 @@
|
|||
|
||||
static struct backlight_device *mbp_backlight_device;
|
||||
|
||||
static struct dmi_system_id __initdata mbp_device_table[] = {
|
||||
{
|
||||
.ident = "3,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "3,2",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "4,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
/* Structure to be passed to the DMI_MATCH function. */
|
||||
struct dmi_match_data {
|
||||
/* I/O resource to allocate. */
|
||||
unsigned long iostart;
|
||||
unsigned long iolen;
|
||||
/* Backlight operations structure. */
|
||||
struct backlight_ops backlight_ops;
|
||||
};
|
||||
|
||||
static int mbp_send_intensity(struct backlight_device *bd)
|
||||
/*
|
||||
* Implementation for MacBooks with Intel chipset.
|
||||
*/
|
||||
static int intel_chipset_send_intensity(struct backlight_device *bd)
|
||||
{
|
||||
int intensity = bd->props.brightness;
|
||||
|
||||
outb(0x04 | (intensity << 4), 0xb3);
|
||||
outb(0xbf, 0xb2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mbp_get_intensity(struct backlight_device *bd)
|
||||
static int intel_chipset_get_intensity(struct backlight_device *bd)
|
||||
{
|
||||
outb(0x03, 0xb3);
|
||||
outb(0xbf, 0xb2);
|
||||
return inb(0xb3) >> 4;
|
||||
}
|
||||
|
||||
static struct backlight_ops mbp_ops = {
|
||||
.options = BL_CORE_SUSPENDRESUME,
|
||||
.get_brightness = mbp_get_intensity,
|
||||
.update_status = mbp_send_intensity,
|
||||
static const struct dmi_match_data intel_chipset_data = {
|
||||
.iostart = 0xb2,
|
||||
.iolen = 2,
|
||||
.backlight_ops = {
|
||||
.options = BL_CORE_SUSPENDRESUME,
|
||||
.get_brightness = intel_chipset_get_intensity,
|
||||
.update_status = intel_chipset_send_intensity,
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementation for MacBooks with Nvidia chipset.
|
||||
*/
|
||||
static int nvidia_chipset_send_intensity(struct backlight_device *bd)
|
||||
{
|
||||
int intensity = bd->props.brightness;
|
||||
|
||||
outb(0x04 | (intensity << 4), 0x52f);
|
||||
outb(0xbf, 0x52e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvidia_chipset_get_intensity(struct backlight_device *bd)
|
||||
{
|
||||
outb(0x03, 0x52f);
|
||||
outb(0xbf, 0x52e);
|
||||
return inb(0x52f) >> 4;
|
||||
}
|
||||
|
||||
static const struct dmi_match_data nvidia_chipset_data = {
|
||||
.iostart = 0x52e,
|
||||
.iolen = 2,
|
||||
.backlight_ops = {
|
||||
.options = BL_CORE_SUSPENDRESUME,
|
||||
.get_brightness = nvidia_chipset_get_intensity,
|
||||
.update_status = nvidia_chipset_send_intensity
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* DMI matching.
|
||||
*/
|
||||
static /* const */ struct dmi_match_data *driver_data;
|
||||
|
||||
static int mbp_dmi_match(const struct dmi_system_id *id)
|
||||
{
|
||||
driver_data = id->driver_data;
|
||||
|
||||
printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id __initdata mbp_device_table[] = {
|
||||
{
|
||||
.callback = mbp_dmi_match,
|
||||
.ident = "MacBookPro 3,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
|
||||
},
|
||||
.driver_data = (void *)&intel_chipset_data,
|
||||
},
|
||||
{
|
||||
.callback = mbp_dmi_match,
|
||||
.ident = "MacBookPro 3,2",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
|
||||
},
|
||||
.driver_data = (void *)&intel_chipset_data,
|
||||
},
|
||||
{
|
||||
.callback = mbp_dmi_match,
|
||||
.ident = "MacBookPro 4,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
|
||||
},
|
||||
.driver_data = (void *)&intel_chipset_data,
|
||||
},
|
||||
{
|
||||
.callback = mbp_dmi_match,
|
||||
.ident = "MacBook 5,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"),
|
||||
},
|
||||
.driver_data = (void *)&nvidia_chipset_data,
|
||||
},
|
||||
{
|
||||
.callback = mbp_dmi_match,
|
||||
.ident = "MacBookAir 2,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"),
|
||||
},
|
||||
.driver_data = (void *)&nvidia_chipset_data,
|
||||
},
|
||||
{
|
||||
.callback = mbp_dmi_match,
|
||||
.ident = "MacBookPro 5,1",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"),
|
||||
},
|
||||
.driver_data = (void *)&nvidia_chipset_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static int __init mbp_init(void)
|
||||
|
@ -80,20 +170,20 @@ static int __init mbp_init(void)
|
|||
if (!dmi_check_system(mbp_device_table))
|
||||
return -ENODEV;
|
||||
|
||||
if (!request_region(0xb2, 2, "Macbook Pro backlight"))
|
||||
if (!request_region(driver_data->iostart, driver_data->iolen,
|
||||
"Macbook Pro backlight"))
|
||||
return -ENXIO;
|
||||
|
||||
mbp_backlight_device = backlight_device_register("mbp_backlight",
|
||||
NULL, NULL,
|
||||
&mbp_ops);
|
||||
NULL, NULL, &driver_data->backlight_ops);
|
||||
if (IS_ERR(mbp_backlight_device)) {
|
||||
release_region(0xb2, 2);
|
||||
release_region(driver_data->iostart, driver_data->iolen);
|
||||
return PTR_ERR(mbp_backlight_device);
|
||||
}
|
||||
|
||||
mbp_backlight_device->props.max_brightness = 15;
|
||||
mbp_backlight_device->props.brightness =
|
||||
mbp_get_intensity(mbp_backlight_device);
|
||||
driver_data->backlight_ops.get_brightness(mbp_backlight_device);
|
||||
backlight_update_status(mbp_backlight_device);
|
||||
|
||||
return 0;
|
||||
|
@ -103,7 +193,7 @@ static void __exit mbp_exit(void)
|
|||
{
|
||||
backlight_device_unregister(mbp_backlight_device);
|
||||
|
||||
release_region(0xb2, 2);
|
||||
release_region(driver_data->iostart, driver_data->iolen);
|
||||
}
|
||||
|
||||
module_init(mbp_init);
|
||||
|
|
Loading…
Reference in a new issue