Skip to content

Commit

Permalink
backlight: Add support for MacBook 5, MacBook Air 2, and MacBook Pro 5
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mario Schwalbe authored and Richard Purdie committed Apr 6, 2009
1 parent 0221c81 commit c78a628
Showing 1 changed file with 126 additions and 36 deletions.
162 changes: 126 additions & 36 deletions drivers/video/backlight/mbp_nvidia_bl.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,73 +27,163 @@

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)
{
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;
Expand All @@ -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);
Expand Down

0 comments on commit c78a628

Please sign in to comment.