All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Backlight: Add backlight type
@ 2010-09-08 16:32 ` Matthew Garrett
  0 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 16:32 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, Richard Purdie, intel-gfx, dri-devel

There may be multiple ways of controlling the backlight on a given machine.
Allow drivers to expose the type of interface they are providing, making
it possible for userspace to make appropriate policy decisions.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: intel-gfx@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org
---
 Documentation/ABI/stable/sysfs-class-backlight  |   20 ++++++++++++++++++++
 drivers/acpi/video.c                            |    1 +
 drivers/gpu/drm/nouveau/nouveau_backlight.c     |    2 ++
 drivers/hid/hid-picolcd.c                       |    1 +
 drivers/macintosh/via-pmu-backlight.c           |    1 +
 drivers/platform/x86/acer-wmi.c                 |    1 +
 drivers/platform/x86/asus-laptop.c              |    1 +
 drivers/platform/x86/asus_acpi.c                |    1 +
 drivers/platform/x86/classmate-laptop.c         |    1 +
 drivers/platform/x86/compal-laptop.c            |    1 +
 drivers/platform/x86/dell-laptop.c              |    1 +
 drivers/platform/x86/eeepc-laptop.c             |    1 +
 drivers/platform/x86/fujitsu-laptop.c           |    1 +
 drivers/platform/x86/msi-laptop.c               |    1 +
 drivers/platform/x86/msi-wmi.c                  |    1 +
 drivers/platform/x86/panasonic-laptop.c         |    1 +
 drivers/platform/x86/sony-laptop.c              |    1 +
 drivers/platform/x86/thinkpad_acpi.c            |    1 +
 drivers/platform/x86/toshiba_acpi.c             |    1 +
 drivers/staging/samsung-laptop/samsung-laptop.c |    1 +
 drivers/usb/misc/appledisplay.c                 |    1 +
 drivers/video/atmel_lcdfb.c                     |    1 +
 drivers/video/aty/aty128fb.c                    |    1 +
 drivers/video/aty/atyfb_base.c                  |    1 +
 drivers/video/aty/radeon_backlight.c            |    1 +
 drivers/video/backlight/88pm860x_bl.c           |    1 +
 drivers/video/backlight/adp5520_bl.c            |    1 +
 drivers/video/backlight/adp8860_bl.c            |    1 +
 drivers/video/backlight/adx_bl.c                |    1 +
 drivers/video/backlight/atmel-pwm-bl.c          |    1 +
 drivers/video/backlight/backlight.c             |   15 +++++++++++++++
 drivers/video/backlight/corgi_lcd.c             |    1 +
 drivers/video/backlight/cr_bllcd.c              |    1 +
 drivers/video/backlight/da903x_bl.c             |    1 +
 drivers/video/backlight/ep93xx_bl.c             |    1 +
 drivers/video/backlight/generic_bl.c            |    1 +
 drivers/video/backlight/hp680_bl.c              |    1 +
 drivers/video/backlight/jornada720_bl.c         |    1 +
 drivers/video/backlight/kb3886_bl.c             |    1 +
 drivers/video/backlight/locomolcd.c             |    1 +
 drivers/video/backlight/max8925_bl.c            |    1 +
 drivers/video/backlight/mbp_nvidia_bl.c         |    1 +
 drivers/video/backlight/omap1_bl.c              |    1 +
 drivers/video/backlight/pcf50633-backlight.c    |    1 +
 drivers/video/backlight/progear_bl.c            |    1 +
 drivers/video/backlight/pwm_bl.c                |    1 +
 drivers/video/backlight/tosa_bl.c               |    1 +
 drivers/video/backlight/wm831x_bl.c             |    1 +
 drivers/video/bf54x-lq043fb.c                   |    1 +
 drivers/video/bfin-t350mcqb-fb.c                |    1 +
 drivers/video/nvidia/nv_backlight.c             |    1 +
 drivers/video/omap2/displays/panel-acx565akm.c  |    1 +
 drivers/video/omap2/displays/panel-taal.c       |    2 ++
 drivers/video/riva/fbdev.c                      |    1 +
 include/linux/backlight.h                       |    8 ++++++++
 55 files changed, 97 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-class-backlight b/Documentation/ABI/stable/sysfs-class-backlight
index 4d637e1..70302f3 100644
--- a/Documentation/ABI/stable/sysfs-class-backlight
+++ b/Documentation/ABI/stable/sysfs-class-backlight
@@ -34,3 +34,23 @@ Contact:	Richard Purdie <rpurdie@rpsys.net>
 Description:
 		Maximum brightness for <backlight>.
 Users:		HAL
+
+What:		/sys/class/backlight/<backlight>/type
+Date:		September 2010
+KernelVersion:	2.6.37
+Contact:	Matthew Garrett <mjg@redhat.com>
+Description:
+		The type of interface controlled by <backlight>.
+		"firmware": The driver uses a standard firmware interface
+		"platform": The driver uses a platform-specific interface
+		"raw": The driver controls hardware registers directly
+
+		In the general case, when multiple backlight
+		interfaces are available for a single device, firmware
+		control should be preferred to platform control should
+		be preferred to raw control. Using a firmware
+		interface reduces the probability of confusion with
+		the hardware and the OS independently updating the
+		backlight state. Platform interfaces are mostly a
+		holdover from pre-standardisation of firmware
+		interfaces.
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 67dec0c..fbae6f5 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -963,6 +963,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 		count++;
 
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_FIRMWARE;
 		props.max_brightness = device->brightness->count - 3;
 		device->backlight = backlight_device_register(name, NULL, device,
 							      &acpi_backlight_ops,
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 406228f..9485af3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -97,6 +97,7 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev)
 		return 0;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 31;
 	bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
 				       &nv40_bl_ops, &props);
@@ -120,6 +121,7 @@ static int nouveau_nv50_backlight_init(struct drm_device *dev)
 		return 0;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 1025;
 	bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
 				       &nv50_bl_ops, &props);
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index bc2e077..3418b82 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -944,6 +944,7 @@ static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *
 	}
 
 	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 0xff;
 	bdev = backlight_device_register(dev_name(dev), dev, data,
 			&picolcd_blops, &props);
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index 1cec02f..364a295 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -163,6 +163,7 @@ void __init pmu_backlight_init()
 	snprintf(name, sizeof(name), "pmubl");
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
 				       &props);
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 2badee2..8849e5a 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -926,6 +926,7 @@ static int __devinit acer_backlight_init(struct device *dev)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = max_brightness;
 	bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
 				       &props);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b756e07..3b26fbdf 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -646,6 +646,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
 	    !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
 	    lcd_switch_handle) {
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = 15;
 
 		bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index ca05aef..3ea8df5 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -1513,6 +1513,7 @@ static int __init asus_acpi_init(void)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 15;
 	asus_backlight_device = backlight_device_register("asus", NULL, NULL,
 							  &asus_backlight_data,
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 341cbfe..0ade3a4 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -562,6 +562,7 @@ static int cmpc_ipml_add(struct acpi_device *acpi)
 		return -ENOMEM;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 7;
 	ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
 					     acpi->handle, &cmpc_bl_ops,
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 097083c..1e66477 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -962,6 +962,7 @@ static int __init compal_init(void)
 	if (!acpi_video_backlight_support()) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = BACKLIGHT_LEVEL_MAX;
 		compalbl_device = backlight_device_register(DRIVER_NAME,
 							    NULL, NULL,
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 4413975..c23429e 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -575,6 +575,7 @@ static int __init dell_init(void)
 	if (max_intensity) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = max_intensity;
 		dell_backlight_device = backlight_device_register("dell_backlight",
 								  &platform_device->dev,
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 6b8e062..0f2f424 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1135,6 +1135,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 15;
 	bd = backlight_device_register(EEEPC_LAPTOP_FILE,
 				       &eeepc->platform_device->dev, eeepc,
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index f44cd26..f5376c6 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -1128,6 +1128,7 @@ static int __init fujitsu_init(void)
 
 		memset(&props, 0, sizeof(struct backlight_properties));
 		max_brightness = fujitsu->max_brightness;
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = max_brightness - 1;
 		fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
 							       NULL, NULL,
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 7e9bb6d..142d385 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -804,6 +804,7 @@ static int __init msi_init(void)
 	} else {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
 		msibl_device = backlight_device_register("msi-laptop-bl", NULL,
 							 NULL, &msibl_ops,
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 42a5469..064d8d6 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -252,6 +252,7 @@ static int __init msi_wmi_init(void)
 	if (!acpi_video_backlight_support()) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
 		backlight = backlight_device_register(DRV_NAME, NULL, NULL,
 						      &msi_backlight_ops,
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index ec01c3d..1c5ab80 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -646,6 +646,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
 	}
 	/* initialize backlight */
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
 	pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
 						   &pcc_backlight_ops, &props);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index e3154ff..c7c97ce 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1297,6 +1297,7 @@ static int sony_nc_add(struct acpi_device *device)
 						&handle))) {
 							struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
 		sony_backlight_device = backlight_device_register("sony", NULL,
 								  NULL,
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e35ed12..8f59af0 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6309,6 +6309,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 		return 1;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = bright_maxlvl;
 	props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
 	ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 7d67a45..f0dc4f0 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -1080,6 +1080,7 @@ static int __init toshiba_acpi_init(void)
 		create_toshiba_proc_entries();
 	}
 
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
 	toshiba_backlight_device = backlight_device_register("toshiba",
 							     &toshiba_acpi.p_dev->dev,
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c
index eb44b60..6c55f38 100644
--- a/drivers/staging/samsung-laptop/samsung-laptop.c
+++ b/drivers/staging/samsung-laptop/samsung-laptop.c
@@ -488,6 +488,7 @@ static int __init samsung_init(void)
 
 	/* create a backlight device to talk to this one */
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = MAX_BRIGHT;
 	backlight_device = backlight_device_register("samsung", &sdev->dev,
 						     NULL, &backlight_ops,
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 1fa6ce3..6562090 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -282,6 +282,7 @@ static int appledisplay_probe(struct usb_interface *iface,
 	snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
 		atomic_inc_return(&count_displays) - 1);
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 0xff;
 	pdata->bd = backlight_device_register(bl_name, NULL, pdata,
 					      &appledisplay_bl_data, &props);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 8dce251..7d40604 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -127,6 +127,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
 		return;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 0xff;
 	bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
 				       &atmel_lcdc_bl_ops, &props);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 34a0851..ac3b7e3 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1818,6 +1818,7 @@ static void aty128_bl_init(struct aty128fb_par *par)
 	snprintf(name, sizeof(name), "aty128bl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &aty128_bl_data,
 				       &props);
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index f8d69ad..f5be5e8 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2241,6 +2241,7 @@ static void aty_bl_init(struct atyfb_par *par)
 	snprintf(name, sizeof(name), "atybl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &aty_bl_data,
 				       &props);
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 256966e..732f665 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -158,6 +158,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
 	snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, rinfo->info->dev, pdata,
 				       &radeon_bl_data, &props);
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index 38ffc3f..d5e51e2 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -227,6 +227,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = MAX_BRIGHTNESS;
 	bl = backlight_device_register(name, &pdev->dev, data,
 					&pm860x_backlight_ops, &props);
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index 9f436e0..af31197 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -303,6 +303,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
 	mutex_init(&data->lock);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = ADP5020_MAX_BRIGHTNESS;
 	bl = backlight_device_register(pdev->name, data->master, data,
 				       &adp5520_bl_ops, &props);
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 3ec2460..a1afb21 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -707,6 +707,7 @@ static int __devinit adp8860_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, data);
 
 	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = ADP8860_MAX_BRIGHTNESS;
 
 	mutex_init(&data->lock);
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
index fe9af12..c861c41 100644
--- a/drivers/video/backlight/adx_bl.c
+++ b/drivers/video/backlight/adx_bl.c
@@ -104,6 +104,7 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 0xff;
 	bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
 					  bl, &adx_backlight_ops, &props);
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index e6a66da..0443a4f 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -168,6 +168,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
 	bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl,
 					  &atmel_pwm_bl_ops, &props);
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index e207810..074502c 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -19,6 +19,12 @@
 #include <asm/backlight.h>
 #endif
 
+static const char *backlight_types[] = {
+	[BACKLIGHT_RAW] = "raw",
+	[BACKLIGHT_PLATFORM] = "platform",
+	[BACKLIGHT_FIRMWARE] = "firmware",
+};
+
 #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
 			   defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
 /* This callback gets called when something important happens inside a
@@ -169,6 +175,14 @@ static ssize_t backlight_store_brightness(struct device *dev,
 	return rc;
 }
 
+static ssize_t backlight_show_type(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
+}
+
 static ssize_t backlight_show_max_brightness(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -234,6 +248,7 @@ static struct device_attribute bl_device_attributes[] = {
 	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
 		     NULL),
 	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR(type, 0444, backlight_show_type, NULL),
 	__ATTR_NULL,
 };
 
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index 1e71c35..af60983 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -562,6 +562,7 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi)
 	lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = pdata->max_intensity;
 	lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd,
 						&corgi_bl_ops, &props);
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index a4f4546..d7d1673 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -193,6 +193,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL,
 					&cr_backlight_ops, &props);
 	if (IS_ERR(bdp)) {
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index 87659ed..62043f1 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -136,6 +136,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
 		da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2,
 				DA9034_WLED_ISET(pdata->output_current));
 
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = max_brightness;
 	bl = backlight_device_register(pdev->name, data->da903x_dev, data,
 				       &da903x_backlight_ops, &props);
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index b0cc491..9f1e389 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -87,6 +87,7 @@ static int __init ep93xxbl_probe(struct platform_device *dev)
 	ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = EP93XX_MAX_BRIGHT;
 	bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl,
 				       &ep93xxbl_ops, &props);
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 312ca61..8c6befd 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -91,6 +91,7 @@ static int genericbl_probe(struct platform_device *pdev)
 		name = machinfo->name;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = machinfo->max_intensity;
 	bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops,
 				       &props);
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 267d23f..38aa002 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -109,6 +109,7 @@ static int __devinit hp680bl_probe(struct platform_device *pdev)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = HP680_MAX_INTENSITY;
 	bd = backlight_device_register("hp680-bl", &pdev->dev, NULL,
 				       &hp680bl_ops, &props);
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index 2f177b3..40e4fa8 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -106,6 +106,7 @@ static int jornada_bl_probe(struct platform_device *pdev)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = BL_MAX_BRIGHT;
 	bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL,
 				       &jornada_bl_ops, &props);
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index f439a86..72dd555 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -149,6 +149,7 @@ static int kb3886bl_probe(struct platform_device *pdev)
 		machinfo->limit_mask = -1;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = machinfo->max_intensity;
 	kb3886_backlight_device = backlight_device_register("kb3886-bl",
 							    &pdev->dev, NULL,
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index d2f5901..bbca312 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -184,6 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev)
 	local_irq_restore(flags);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 4;
 	locomolcd_bl_device = backlight_device_register("locomo-bl",
 							&ldev->dev, NULL,
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index b2b2c7b..8d25610 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -136,6 +136,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
 	data->current_brightness = 0;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = MAX_BRIGHTNESS;
 	bl = backlight_device_register(name, &pdev->dev, data,
 					&max8925_backlight_ops, &props);
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 9fb533f..1e5d10a 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -349,6 +349,7 @@ static int __init mbp_init(void)
 		return -ENXIO;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 15;
 	mbp_backlight_device = backlight_device_register("mbp_backlight", NULL,
 							 NULL,
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index d3bc562..08d26a7 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -146,6 +146,7 @@ static int omapbl_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = OMAPBL_MAX_INTENSITY;
 	dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops,
 					&props);
diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c
index 3c424f7..ef5628d 100644
--- a/drivers/video/backlight/pcf50633-backlight.c
+++ b/drivers/video/backlight/pcf50633-backlight.c
@@ -112,6 +112,7 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
 	if (!pcf_bl)
 		return -ENOMEM;
 
+	bl_props.type = BACKLIGHT_RAW;
 	bl_props.max_brightness = 0x3f;
 	bl_props.power = FB_BLANK_UNBLANK;
 
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
index 809278c..6af183d 100644
--- a/drivers/video/backlight/progear_bl.c
+++ b/drivers/video/backlight/progear_bl.c
@@ -84,6 +84,7 @@ static int progearbl_probe(struct platform_device *pdev)
 	pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
 	progear_backlight_device = backlight_device_register("progear-bl",
 							     &pdev->dev, NULL,
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 5504435..647862c 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -103,6 +103,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		dev_dbg(&pdev->dev, "got pwm for backlight\n");
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = data->max_brightness;
 	bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
 				       &pwm_backlight_ops, &props);
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 2a04b38..425a736 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -102,6 +102,7 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
 	data->i2c = client;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 512 - 1;
 	data->bl = backlight_device_register("tosa-bl", &client->dev, data,
 					     &bl_ops, &props);
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
index 08fd87f..d4c6eb2 100644
--- a/drivers/video/backlight/wm831x_bl.c
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -193,6 +193,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
 	data->current_brightness = 0;
 	data->isink_reg = isink_reg;
 
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = max_isel;
 	bl = backlight_device_register("wm831x", &pdev->dev, data,
 				       &wm831x_backlight_ops, &props);
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index b020ba7..1efeadc 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -649,6 +649,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 	}
 #ifndef NO_BL_SUPPORT
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 255;
 	bl_dev = backlight_device_register("bf54x-bl", NULL, NULL,
 					   &bfin_lq043fb_bl_ops, &props);
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 7a50272..4ce7292 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -545,6 +545,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 	}
 #ifndef NO_BL_SUPPORT
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 255;
 	bl_dev = backlight_device_register("bf52x-bl", NULL, NULL,
 					   &bfin_lq043fb_bl_ops, &props);
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 2fb552a..74ba5da 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -111,6 +111,7 @@ void nvidia_bl_init(struct nvidia_par *par)
 	snprintf(name, sizeof(name), "nvidiabl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops,
 				       &props);
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 07fbb8a..eb76021 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -534,6 +534,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
 
 	props.fb_blank = FB_BLANK_UNBLANK;
 	props.power = FB_BLANK_UNBLANK;
+	props.type = BACKLIGHT_RAW;
 
 	bldev = backlight_device_register("acx565akm", &md->spi->dev,
 			md, &acx565akm_bl_ops, &props);
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index e1c765d..d16a7cd 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -729,6 +729,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 		props.max_brightness = 255;
 	else
 		props.max_brightness = 127;
+
+	props.type = BACKLIGHT_RAW;
 	bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
 					  &taal_bl_ops, &props);
 	if (IS_ERR(bldev)) {
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 618f36b..9058ba5 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -355,6 +355,7 @@ static void riva_bl_init(struct riva_par *par)
 	snprintf(name, sizeof(name), "rivabl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &riva_bl_ops,
 				       &props);
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 4a3d52e..5b45437 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -32,6 +32,12 @@ enum backlight_update_reason {
 	BACKLIGHT_UPDATE_SYSFS,
 };
 
+enum backlight_type {
+	BACKLIGHT_RAW,
+	BACKLIGHT_PLATFORM,
+	BACKLIGHT_FIRMWARE,
+};
+
 struct backlight_device;
 struct fb_info;
 
@@ -62,6 +68,8 @@ struct backlight_properties {
 	/* FB Blanking active? (values as for power) */
 	/* Due to be removed, please use (state & BL_CORE_FBBLANK) */
 	int fb_blank;
+	/* Backlight type */
+	enum backlight_type type;
 	/* Flags used to signal drivers of state changes */
 	/* Upper 4 bits are reserved for driver internal use */
 	unsigned int state;
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH] Backlight: Add backlight type
@ 2010-09-08 16:32 ` Matthew Garrett
  0 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 16:32 UTC (permalink / raw)
  To: linux-kernel; +Cc: intel-gfx, Richard Purdie, dri-devel, Matthew Garrett

There may be multiple ways of controlling the backlight on a given machine.
Allow drivers to expose the type of interface they are providing, making
it possible for userspace to make appropriate policy decisions.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: intel-gfx@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org
---
 Documentation/ABI/stable/sysfs-class-backlight  |   20 ++++++++++++++++++++
 drivers/acpi/video.c                            |    1 +
 drivers/gpu/drm/nouveau/nouveau_backlight.c     |    2 ++
 drivers/hid/hid-picolcd.c                       |    1 +
 drivers/macintosh/via-pmu-backlight.c           |    1 +
 drivers/platform/x86/acer-wmi.c                 |    1 +
 drivers/platform/x86/asus-laptop.c              |    1 +
 drivers/platform/x86/asus_acpi.c                |    1 +
 drivers/platform/x86/classmate-laptop.c         |    1 +
 drivers/platform/x86/compal-laptop.c            |    1 +
 drivers/platform/x86/dell-laptop.c              |    1 +
 drivers/platform/x86/eeepc-laptop.c             |    1 +
 drivers/platform/x86/fujitsu-laptop.c           |    1 +
 drivers/platform/x86/msi-laptop.c               |    1 +
 drivers/platform/x86/msi-wmi.c                  |    1 +
 drivers/platform/x86/panasonic-laptop.c         |    1 +
 drivers/platform/x86/sony-laptop.c              |    1 +
 drivers/platform/x86/thinkpad_acpi.c            |    1 +
 drivers/platform/x86/toshiba_acpi.c             |    1 +
 drivers/staging/samsung-laptop/samsung-laptop.c |    1 +
 drivers/usb/misc/appledisplay.c                 |    1 +
 drivers/video/atmel_lcdfb.c                     |    1 +
 drivers/video/aty/aty128fb.c                    |    1 +
 drivers/video/aty/atyfb_base.c                  |    1 +
 drivers/video/aty/radeon_backlight.c            |    1 +
 drivers/video/backlight/88pm860x_bl.c           |    1 +
 drivers/video/backlight/adp5520_bl.c            |    1 +
 drivers/video/backlight/adp8860_bl.c            |    1 +
 drivers/video/backlight/adx_bl.c                |    1 +
 drivers/video/backlight/atmel-pwm-bl.c          |    1 +
 drivers/video/backlight/backlight.c             |   15 +++++++++++++++
 drivers/video/backlight/corgi_lcd.c             |    1 +
 drivers/video/backlight/cr_bllcd.c              |    1 +
 drivers/video/backlight/da903x_bl.c             |    1 +
 drivers/video/backlight/ep93xx_bl.c             |    1 +
 drivers/video/backlight/generic_bl.c            |    1 +
 drivers/video/backlight/hp680_bl.c              |    1 +
 drivers/video/backlight/jornada720_bl.c         |    1 +
 drivers/video/backlight/kb3886_bl.c             |    1 +
 drivers/video/backlight/locomolcd.c             |    1 +
 drivers/video/backlight/max8925_bl.c            |    1 +
 drivers/video/backlight/mbp_nvidia_bl.c         |    1 +
 drivers/video/backlight/omap1_bl.c              |    1 +
 drivers/video/backlight/pcf50633-backlight.c    |    1 +
 drivers/video/backlight/progear_bl.c            |    1 +
 drivers/video/backlight/pwm_bl.c                |    1 +
 drivers/video/backlight/tosa_bl.c               |    1 +
 drivers/video/backlight/wm831x_bl.c             |    1 +
 drivers/video/bf54x-lq043fb.c                   |    1 +
 drivers/video/bfin-t350mcqb-fb.c                |    1 +
 drivers/video/nvidia/nv_backlight.c             |    1 +
 drivers/video/omap2/displays/panel-acx565akm.c  |    1 +
 drivers/video/omap2/displays/panel-taal.c       |    2 ++
 drivers/video/riva/fbdev.c                      |    1 +
 include/linux/backlight.h                       |    8 ++++++++
 55 files changed, 97 insertions(+), 0 deletions(-)

diff --git a/Documentation/ABI/stable/sysfs-class-backlight b/Documentation/ABI/stable/sysfs-class-backlight
index 4d637e1..70302f3 100644
--- a/Documentation/ABI/stable/sysfs-class-backlight
+++ b/Documentation/ABI/stable/sysfs-class-backlight
@@ -34,3 +34,23 @@ Contact:	Richard Purdie <rpurdie@rpsys.net>
 Description:
 		Maximum brightness for <backlight>.
 Users:		HAL
+
+What:		/sys/class/backlight/<backlight>/type
+Date:		September 2010
+KernelVersion:	2.6.37
+Contact:	Matthew Garrett <mjg@redhat.com>
+Description:
+		The type of interface controlled by <backlight>.
+		"firmware": The driver uses a standard firmware interface
+		"platform": The driver uses a platform-specific interface
+		"raw": The driver controls hardware registers directly
+
+		In the general case, when multiple backlight
+		interfaces are available for a single device, firmware
+		control should be preferred to platform control should
+		be preferred to raw control. Using a firmware
+		interface reduces the probability of confusion with
+		the hardware and the OS independently updating the
+		backlight state. Platform interfaces are mostly a
+		holdover from pre-standardisation of firmware
+		interfaces.
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 67dec0c..fbae6f5 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -963,6 +963,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 		count++;
 
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_FIRMWARE;
 		props.max_brightness = device->brightness->count - 3;
 		device->backlight = backlight_device_register(name, NULL, device,
 							      &acpi_backlight_ops,
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 406228f..9485af3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -97,6 +97,7 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev)
 		return 0;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 31;
 	bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
 				       &nv40_bl_ops, &props);
@@ -120,6 +121,7 @@ static int nouveau_nv50_backlight_init(struct drm_device *dev)
 		return 0;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 1025;
 	bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
 				       &nv50_bl_ops, &props);
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index bc2e077..3418b82 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -944,6 +944,7 @@ static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *
 	}
 
 	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 0xff;
 	bdev = backlight_device_register(dev_name(dev), dev, data,
 			&picolcd_blops, &props);
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index 1cec02f..364a295 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -163,6 +163,7 @@ void __init pmu_backlight_init()
 	snprintf(name, sizeof(name), "pmubl");
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
 				       &props);
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 2badee2..8849e5a 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -926,6 +926,7 @@ static int __devinit acer_backlight_init(struct device *dev)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = max_brightness;
 	bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
 				       &props);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b756e07..3b26fbdf 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -646,6 +646,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
 	    !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) &&
 	    lcd_switch_handle) {
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = 15;
 
 		bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index ca05aef..3ea8df5 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -1513,6 +1513,7 @@ static int __init asus_acpi_init(void)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 15;
 	asus_backlight_device = backlight_device_register("asus", NULL, NULL,
 							  &asus_backlight_data,
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 341cbfe..0ade3a4 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -562,6 +562,7 @@ static int cmpc_ipml_add(struct acpi_device *acpi)
 		return -ENOMEM;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 7;
 	ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
 					     acpi->handle, &cmpc_bl_ops,
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 097083c..1e66477 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -962,6 +962,7 @@ static int __init compal_init(void)
 	if (!acpi_video_backlight_support()) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = BACKLIGHT_LEVEL_MAX;
 		compalbl_device = backlight_device_register(DRIVER_NAME,
 							    NULL, NULL,
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 4413975..c23429e 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -575,6 +575,7 @@ static int __init dell_init(void)
 	if (max_intensity) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = max_intensity;
 		dell_backlight_device = backlight_device_register("dell_backlight",
 								  &platform_device->dev,
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 6b8e062..0f2f424 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1135,6 +1135,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 15;
 	bd = backlight_device_register(EEEPC_LAPTOP_FILE,
 				       &eeepc->platform_device->dev, eeepc,
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index f44cd26..f5376c6 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -1128,6 +1128,7 @@ static int __init fujitsu_init(void)
 
 		memset(&props, 0, sizeof(struct backlight_properties));
 		max_brightness = fujitsu->max_brightness;
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = max_brightness - 1;
 		fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
 							       NULL, NULL,
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 7e9bb6d..142d385 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -804,6 +804,7 @@ static int __init msi_init(void)
 	} else {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
 		msibl_device = backlight_device_register("msi-laptop-bl", NULL,
 							 NULL, &msibl_ops,
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 42a5469..064d8d6 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -252,6 +252,7 @@ static int __init msi_wmi_init(void)
 	if (!acpi_video_backlight_support()) {
 		struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
 		backlight = backlight_device_register(DRV_NAME, NULL, NULL,
 						      &msi_backlight_ops,
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index ec01c3d..1c5ab80 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -646,6 +646,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
 	}
 	/* initialize backlight */
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
 	pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
 						   &pcc_backlight_ops, &props);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index e3154ff..c7c97ce 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1297,6 +1297,7 @@ static int sony_nc_add(struct acpi_device *device)
 						&handle))) {
 							struct backlight_properties props;
 		memset(&props, 0, sizeof(struct backlight_properties));
+		props.type = BACKLIGHT_PLATFORM;
 		props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
 		sony_backlight_device = backlight_device_register("sony", NULL,
 								  NULL,
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e35ed12..8f59af0 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6309,6 +6309,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
 		return 1;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = bright_maxlvl;
 	props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
 	ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 7d67a45..f0dc4f0 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -1080,6 +1080,7 @@ static int __init toshiba_acpi_init(void)
 		create_toshiba_proc_entries();
 	}
 
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
 	toshiba_backlight_device = backlight_device_register("toshiba",
 							     &toshiba_acpi.p_dev->dev,
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c
index eb44b60..6c55f38 100644
--- a/drivers/staging/samsung-laptop/samsung-laptop.c
+++ b/drivers/staging/samsung-laptop/samsung-laptop.c
@@ -488,6 +488,7 @@ static int __init samsung_init(void)
 
 	/* create a backlight device to talk to this one */
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = MAX_BRIGHT;
 	backlight_device = backlight_device_register("samsung", &sdev->dev,
 						     NULL, &backlight_ops,
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 1fa6ce3..6562090 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -282,6 +282,7 @@ static int appledisplay_probe(struct usb_interface *iface,
 	snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
 		atomic_inc_return(&count_displays) - 1);
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_PLATFORM;
 	props.max_brightness = 0xff;
 	pdata->bd = backlight_device_register(bl_name, NULL, pdata,
 					      &appledisplay_bl_data, &props);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 8dce251..7d40604 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -127,6 +127,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
 		return;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 0xff;
 	bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
 				       &atmel_lcdc_bl_ops, &props);
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 34a0851..ac3b7e3 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1818,6 +1818,7 @@ static void aty128_bl_init(struct aty128fb_par *par)
 	snprintf(name, sizeof(name), "aty128bl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &aty128_bl_data,
 				       &props);
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index f8d69ad..f5be5e8 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2241,6 +2241,7 @@ static void aty_bl_init(struct atyfb_par *par)
 	snprintf(name, sizeof(name), "atybl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &aty_bl_data,
 				       &props);
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 256966e..732f665 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -158,6 +158,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
 	snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, rinfo->info->dev, pdata,
 				       &radeon_bl_data, &props);
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index 38ffc3f..d5e51e2 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -227,6 +227,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = MAX_BRIGHTNESS;
 	bl = backlight_device_register(name, &pdev->dev, data,
 					&pm860x_backlight_ops, &props);
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index 9f436e0..af31197 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -303,6 +303,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
 	mutex_init(&data->lock);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = ADP5020_MAX_BRIGHTNESS;
 	bl = backlight_device_register(pdev->name, data->master, data,
 				       &adp5520_bl_ops, &props);
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 3ec2460..a1afb21 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -707,6 +707,7 @@ static int __devinit adp8860_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, data);
 
 	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = ADP8860_MAX_BRIGHTNESS;
 
 	mutex_init(&data->lock);
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
index fe9af12..c861c41 100644
--- a/drivers/video/backlight/adx_bl.c
+++ b/drivers/video/backlight/adx_bl.c
@@ -104,6 +104,7 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 0xff;
 	bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
 					  bl, &adx_backlight_ops, &props);
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index e6a66da..0443a4f 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -168,6 +168,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
 	bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl,
 					  &atmel_pwm_bl_ops, &props);
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index e207810..074502c 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -19,6 +19,12 @@
 #include <asm/backlight.h>
 #endif
 
+static const char *backlight_types[] = {
+	[BACKLIGHT_RAW] = "raw",
+	[BACKLIGHT_PLATFORM] = "platform",
+	[BACKLIGHT_FIRMWARE] = "firmware",
+};
+
 #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
 			   defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
 /* This callback gets called when something important happens inside a
@@ -169,6 +175,14 @@ static ssize_t backlight_store_brightness(struct device *dev,
 	return rc;
 }
 
+static ssize_t backlight_show_type(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
+}
+
 static ssize_t backlight_show_max_brightness(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -234,6 +248,7 @@ static struct device_attribute bl_device_attributes[] = {
 	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
 		     NULL),
 	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR(type, 0444, backlight_show_type, NULL),
 	__ATTR_NULL,
 };
 
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index 1e71c35..af60983 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -562,6 +562,7 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi)
 	lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = pdata->max_intensity;
 	lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd,
 						&corgi_bl_ops, &props);
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index a4f4546..d7d1673 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -193,6 +193,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
 	}
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL,
 					&cr_backlight_ops, &props);
 	if (IS_ERR(bdp)) {
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index 87659ed..62043f1 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -136,6 +136,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
 		da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2,
 				DA9034_WLED_ISET(pdata->output_current));
 
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = max_brightness;
 	bl = backlight_device_register(pdev->name, data->da903x_dev, data,
 				       &da903x_backlight_ops, &props);
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index b0cc491..9f1e389 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -87,6 +87,7 @@ static int __init ep93xxbl_probe(struct platform_device *dev)
 	ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = EP93XX_MAX_BRIGHT;
 	bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl,
 				       &ep93xxbl_ops, &props);
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 312ca61..8c6befd 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -91,6 +91,7 @@ static int genericbl_probe(struct platform_device *pdev)
 		name = machinfo->name;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = machinfo->max_intensity;
 	bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops,
 				       &props);
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 267d23f..38aa002 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -109,6 +109,7 @@ static int __devinit hp680bl_probe(struct platform_device *pdev)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = HP680_MAX_INTENSITY;
 	bd = backlight_device_register("hp680-bl", &pdev->dev, NULL,
 				       &hp680bl_ops, &props);
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index 2f177b3..40e4fa8 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -106,6 +106,7 @@ static int jornada_bl_probe(struct platform_device *pdev)
 	struct backlight_device *bd;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = BL_MAX_BRIGHT;
 	bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL,
 				       &jornada_bl_ops, &props);
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index f439a86..72dd555 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -149,6 +149,7 @@ static int kb3886bl_probe(struct platform_device *pdev)
 		machinfo->limit_mask = -1;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = machinfo->max_intensity;
 	kb3886_backlight_device = backlight_device_register("kb3886-bl",
 							    &pdev->dev, NULL,
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index d2f5901..bbca312 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -184,6 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev)
 	local_irq_restore(flags);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 4;
 	locomolcd_bl_device = backlight_device_register("locomo-bl",
 							&ldev->dev, NULL,
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index b2b2c7b..8d25610 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -136,6 +136,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
 	data->current_brightness = 0;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = MAX_BRIGHTNESS;
 	bl = backlight_device_register(name, &pdev->dev, data,
 					&max8925_backlight_ops, &props);
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 9fb533f..1e5d10a 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -349,6 +349,7 @@ static int __init mbp_init(void)
 		return -ENXIO;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 15;
 	mbp_backlight_device = backlight_device_register("mbp_backlight", NULL,
 							 NULL,
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index d3bc562..08d26a7 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -146,6 +146,7 @@ static int omapbl_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = OMAPBL_MAX_INTENSITY;
 	dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops,
 					&props);
diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c
index 3c424f7..ef5628d 100644
--- a/drivers/video/backlight/pcf50633-backlight.c
+++ b/drivers/video/backlight/pcf50633-backlight.c
@@ -112,6 +112,7 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
 	if (!pcf_bl)
 		return -ENOMEM;
 
+	bl_props.type = BACKLIGHT_RAW;
 	bl_props.max_brightness = 0x3f;
 	bl_props.power = FB_BLANK_UNBLANK;
 
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
index 809278c..6af183d 100644
--- a/drivers/video/backlight/progear_bl.c
+++ b/drivers/video/backlight/progear_bl.c
@@ -84,6 +84,7 @@ static int progearbl_probe(struct platform_device *pdev)
 	pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
 	progear_backlight_device = backlight_device_register("progear-bl",
 							     &pdev->dev, NULL,
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 5504435..647862c 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -103,6 +103,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		dev_dbg(&pdev->dev, "got pwm for backlight\n");
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = data->max_brightness;
 	bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
 				       &pwm_backlight_ops, &props);
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 2a04b38..425a736 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -102,6 +102,7 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
 	data->i2c = client;
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 512 - 1;
 	data->bl = backlight_device_register("tosa-bl", &client->dev, data,
 					     &bl_ops, &props);
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
index 08fd87f..d4c6eb2 100644
--- a/drivers/video/backlight/wm831x_bl.c
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -193,6 +193,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
 	data->current_brightness = 0;
 	data->isink_reg = isink_reg;
 
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = max_isel;
 	bl = backlight_device_register("wm831x", &pdev->dev, data,
 				       &wm831x_backlight_ops, &props);
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index b020ba7..1efeadc 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -649,6 +649,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 	}
 #ifndef NO_BL_SUPPORT
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 255;
 	bl_dev = backlight_device_register("bf54x-bl", NULL, NULL,
 					   &bfin_lq043fb_bl_ops, &props);
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 7a50272..4ce7292 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -545,6 +545,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 	}
 #ifndef NO_BL_SUPPORT
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = 255;
 	bl_dev = backlight_device_register("bf52x-bl", NULL, NULL,
 					   &bfin_lq043fb_bl_ops, &props);
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 2fb552a..74ba5da 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -111,6 +111,7 @@ void nvidia_bl_init(struct nvidia_par *par)
 	snprintf(name, sizeof(name), "nvidiabl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops,
 				       &props);
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 07fbb8a..eb76021 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -534,6 +534,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
 
 	props.fb_blank = FB_BLANK_UNBLANK;
 	props.power = FB_BLANK_UNBLANK;
+	props.type = BACKLIGHT_RAW;
 
 	bldev = backlight_device_register("acx565akm", &md->spi->dev,
 			md, &acx565akm_bl_ops, &props);
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index e1c765d..d16a7cd 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -729,6 +729,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
 		props.max_brightness = 255;
 	else
 		props.max_brightness = 127;
+
+	props.type = BACKLIGHT_RAW;
 	bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
 					  &taal_bl_ops, &props);
 	if (IS_ERR(bldev)) {
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 618f36b..9058ba5 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -355,6 +355,7 @@ static void riva_bl_init(struct riva_par *par)
 	snprintf(name, sizeof(name), "rivabl%d", info->node);
 
 	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 	bd = backlight_device_register(name, info->dev, par, &riva_bl_ops,
 				       &props);
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 4a3d52e..5b45437 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -32,6 +32,12 @@ enum backlight_update_reason {
 	BACKLIGHT_UPDATE_SYSFS,
 };
 
+enum backlight_type {
+	BACKLIGHT_RAW,
+	BACKLIGHT_PLATFORM,
+	BACKLIGHT_FIRMWARE,
+};
+
 struct backlight_device;
 struct fb_info;
 
@@ -62,6 +68,8 @@ struct backlight_properties {
 	/* FB Blanking active? (values as for power) */
 	/* Due to be removed, please use (state & BL_CORE_FBBLANK) */
 	int fb_blank;
+	/* Backlight type */
+	enum backlight_type type;
 	/* Flags used to signal drivers of state changes */
 	/* Upper 4 bits are reserved for driver internal use */
 	unsigned int state;
-- 
1.7.2.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH] i915: Add native backlight control
  2010-09-08 16:32 ` Matthew Garrett
@ 2010-09-08 16:32   ` Matthew Garrett
  -1 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 16:32 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett, intel-gfx

Not all systems expose a firmware or platform mechanism for changing the
backlight intensity on i915, so add native driver support.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Cc: intel-gfx <intel-gfx@lists.freedesktop.org>
---
 drivers/gpu/drm/i915/i915_drv.h      |    3 +
 drivers/gpu/drm/i915/i915_opregion.c |   60 +-----------
 drivers/gpu/drm/i915/intel_drv.h     |    3 +
 drivers/gpu/drm/i915/intel_lvds.c    |  177 ++++++++++++++++++++++++++++++----
 4 files changed, 170 insertions(+), 73 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index af4a263..36c4b407 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -34,6 +34,7 @@
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
+#include <linux/backlight.h>
 
 /* General customization:
  */
@@ -663,6 +664,8 @@ typedef struct drm_i915_private {
 
 	/* list of fbdev register on this device */
 	struct intel_fbdev *fbdev;
+
+	struct backlight_device *backlight;
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
index ea5d3fe..de199dd 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -31,9 +31,9 @@
 #include "drmP.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
 #define PCI_ASLS 0xfc
 
 #define OPREGION_SZ            (8*1024)
@@ -147,8 +147,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 blc_pwm_ctl, blc_pwm_ctl2;
-	u32 max_backlight, level, shift;
+	u32 max = intel_lvds_get_max_backlight(dev);
 
 	if (!(bclp & ASLE_BCLP_VALID))
 		return ASLE_BACKLIGHT_FAILED;
@@ -157,27 +156,8 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 	if (bclp < 0 || bclp > 255)
 		return ASLE_BACKLIGHT_FAILED;
 
-	blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-	blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
-	if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
-		pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
-	else {
-		if (IS_PINEVIEW(dev)) {
-			blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
-			max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
-		} else {
-			blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-			max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
-		}
-		level = (bclp * max_backlight) / 255;
-		I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
-	}
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+	asle->cblv = (bclp * 100 / 255) | ASLE_CBLV_VALID;
+	intel_lvds_set_backlight(dev, max * bclp / 255);
 
 	return 0;
 }
@@ -243,36 +223,6 @@ void opregion_asle_intr(struct drm_device *dev)
 	asle->aslc = asle_stat;
 }
 
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 cpu_pwm_ctl, pch_pwm_ctl2;
-	u32 max_backlight, level;
-
-	if (!(bclp & ASLE_BCLP_VALID))
-		return ASLE_BACKLIGHT_FAILED;
-
-	bclp &= ASLE_BCLP_MSK;
-	if (bclp < 0 || bclp > 255)
-		return ASLE_BACKLIGHT_FAILED;
-
-	cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
-	pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-	/* get the max PWM frequency */
-	max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
-	/* calculate the expected PMW frequency */
-	level = (bclp * max_backlight) / 255;
-	/* reserve the high 16 bits */
-	cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
-	/* write the updated PWM frequency */
-	I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-	return 0;
-}
-
 void ironlake_opregion_gse_intr(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -296,7 +246,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev)
 	}
 
 	if (asle_req & ASLE_SET_BACKLIGHT)
-		asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
+		asle_stat |= asle_set_backlight(dev, asle->bclp);
 
 	if (asle_req & ASLE_SET_PFIT) {
 		DRM_DEBUG_DRIVER("Pfit is not supported\n");
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ad312ca..a0f870f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -201,6 +201,9 @@ extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
 extern void intel_lvds_init(struct drm_device *dev);
+extern u32 intel_lvds_get_max_backlight(struct drm_device *dev);
+extern u32 intel_lvds_get_backlight(struct drm_device *dev);
+extern void intel_lvds_set_backlight(struct drm_device *dev, int level);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index b819c10..0ab5891 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -39,6 +39,7 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 #include <linux/acpi.h>
+#include <linux/backlight.h>
 
 /* Private structure for the integrated LVDS support */
 struct intel_lvds {
@@ -54,42 +55,178 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
 }
 
 /**
- * Sets the backlight level.
- *
- * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
+ * Returns the maximum level of the backlight duty cycle field.
  */
-static void intel_lvds_set_backlight(struct drm_device *dev, int level)
+u32 intel_lvds_get_max_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 blc_pwm_ctl, reg;
+	u32 reg;
+	int value;
+	bool combo;
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_CPU_CTL;
+	if (IS_I965G(dev))
+		combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+	else
+		combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	if (IS_IRONLAKE(dev))
+		reg = BLC_PWM_PCH_CTL2;
 	else
 		reg = BLC_PWM_CTL;
 
-	blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-	I915_WRITE(reg, (blc_pwm_ctl |
-				 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+	value = ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+		 BACKLIGHT_MODULATION_FREQ_SHIFT);
+
+	if (!IS_PINEVIEW(dev))
+		value *= 2;
+
+	if (combo) {
+		value *= 0xff;
+		value /= 2;
+	}
+
+	return value;
 }
 
 /**
- * Returns the maximum level of the backlight duty cycle field.
+ * Returns the level of the backlight duty cycle field.
  */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+u32 intel_lvds_get_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 reg;
+	u8 lbpc;
+	int value;
+	bool combo;
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_PCH_CTL2;
+	if (IS_I965G(dev))
+		combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+	else
+		combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	if (IS_IRONLAKE(dev))
+		reg = BLC_PWM_CPU_CTL;
+	else
+		reg = BLC_PWM_CTL;
+
+	value = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK;
+
+	if (IS_PINEVIEW(dev))
+		value /= 2;
+
+	if (combo) {
+		value &= ~0x1;
+		pci_read_config_byte(dev->pdev, LBB, &lbpc);
+		value *= lbpc;
+		value /= 2;
+	}
+
+	return value;
+}
+
+/**
+ * Sets the backlight level.
+  *
+  * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
+  */
+void intel_lvds_set_backlight(struct drm_device *dev, int level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 blc_pwm_ctl, reg;
+	bool combo;
+	u8 lbpc;
+
+	if (IS_I965G(dev))
+		combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+	else
+		combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	if (IS_IRONLAKE(dev))
+		reg = BLC_PWM_CPU_CTL;
 	else
 		reg = BLC_PWM_CTL;
 
-	return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
-		BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+	if (combo) {
+		int maximum = intel_lvds_get_max_backlight(dev);
+		lbpc = level * 0xfe / maximum;
+		lbpc += 1;
+		pci_write_config_byte(dev->pdev, LBB, lbpc);
+		level /= lbpc;
+		level <<= 1;
+	}
+
+	if (IS_PINEVIEW(dev)) {
+		blc_pwm_ctl = I915_READ(reg) & ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+		I915_WRITE(reg, (blc_pwm_ctl |
+			 (level << (BACKLIGHT_DUTY_CYCLE_SHIFT + 1))));
+	} else {
+		blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+		I915_WRITE(reg, blc_pwm_ctl |
+		   (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
+	}
 }
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_lvds_update_status(struct backlight_device *bd)
+{
+	struct drm_device *dev = bl_get_data(bd);
+	intel_lvds_set_backlight(dev, bd->props.brightness);
+	return 0;
+}
+
+static int intel_lvds_get_brightness(struct backlight_device *bd)
+{
+	struct drm_device *dev = bl_get_data(bd);
+	return intel_lvds_get_backlight(dev);
+}
+
+static const struct backlight_ops intel_lvds_bl_ops = {
+	.update_status = intel_lvds_update_status,
+	.get_brightness = intel_lvds_get_brightness,
+};
+
+static int intel_lvds_backlight_setup(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct backlight_properties props;
+
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = intel_lvds_get_max_backlight(dev);
+	dev_priv->backlight =
+		backlight_device_register("intel_backlight",
+					  &dev_priv->int_lvds_connector->kdev,
+					  dev,
+					  &intel_lvds_bl_ops,
+					  &props);
+
+	if (IS_ERR(dev_priv->backlight)) {
+		DRM_ERROR("Failed to register backlight: %ld\n",
+			  PTR_ERR(dev_priv->backlight));
+		dev_priv->backlight = NULL;
+		return -ENODEV;
+	}
+	dev_priv->backlight->props.brightness = intel_lvds_get_backlight(dev);
+	return 0;
+}
+
+static void intel_lvds_backlight_destroy(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->backlight)
+		backlight_device_unregister(dev_priv->backlight);
+}
+#else
+static int intel_lvds_backlight_setup(struct drm_device *dev)
+{
+	return 0;
+}
+
+static void intel_lvds_backlight_destroy(struct drm_device *dev)
+{
+	return;
+}
+#endif
+
 /**
  * Sets the power state for the panel.
  */
@@ -394,8 +531,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
 		reg = BLC_PWM_CTL;
 
 	dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
-	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-				       BACKLIGHT_DUTY_CYCLE_MASK);
+	dev_priv->backlight_duty_cycle = intel_lvds_get_backlight(dev);
 
 	intel_lvds_set_power(dev, false);
 }
@@ -573,6 +709,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	intel_lvds_backlight_destroy(dev);
+
 	if (dev_priv->lid_notifier.notifier_call)
 		acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
 	drm_sysfs_connector_remove(connector);
@@ -992,6 +1130,9 @@ out:
 	/* keep the LVDS connector */
 	dev_priv->int_lvds_connector = connector;
 	drm_sysfs_connector_add(connector);
+
+	intel_lvds_backlight_setup(dev);
+
 	return;
 
 failed:
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH] i915: Add native backlight control
@ 2010-09-08 16:32   ` Matthew Garrett
  0 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 16:32 UTC (permalink / raw)
  To: linux-kernel; +Cc: intel-gfx, Matthew Garrett

Not all systems expose a firmware or platform mechanism for changing the
backlight intensity on i915, so add native driver support.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Cc: intel-gfx <intel-gfx@lists.freedesktop.org>
---
 drivers/gpu/drm/i915/i915_drv.h      |    3 +
 drivers/gpu/drm/i915/i915_opregion.c |   60 +-----------
 drivers/gpu/drm/i915/intel_drv.h     |    3 +
 drivers/gpu/drm/i915/intel_lvds.c    |  177 ++++++++++++++++++++++++++++++----
 4 files changed, 170 insertions(+), 73 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index af4a263..36c4b407 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -34,6 +34,7 @@
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
+#include <linux/backlight.h>
 
 /* General customization:
  */
@@ -663,6 +664,8 @@ typedef struct drm_i915_private {
 
 	/* list of fbdev register on this device */
 	struct intel_fbdev *fbdev;
+
+	struct backlight_device *backlight;
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
index ea5d3fe..de199dd 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -31,9 +31,9 @@
 #include "drmP.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
 #define PCI_ASLS 0xfc
 
 #define OPREGION_SZ            (8*1024)
@@ -147,8 +147,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 blc_pwm_ctl, blc_pwm_ctl2;
-	u32 max_backlight, level, shift;
+	u32 max = intel_lvds_get_max_backlight(dev);
 
 	if (!(bclp & ASLE_BCLP_VALID))
 		return ASLE_BACKLIGHT_FAILED;
@@ -157,27 +156,8 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 	if (bclp < 0 || bclp > 255)
 		return ASLE_BACKLIGHT_FAILED;
 
-	blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-	blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
-	if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
-		pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
-	else {
-		if (IS_PINEVIEW(dev)) {
-			blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
-			max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
-		} else {
-			blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-			max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
-		}
-		level = (bclp * max_backlight) / 255;
-		I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
-	}
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+	asle->cblv = (bclp * 100 / 255) | ASLE_CBLV_VALID;
+	intel_lvds_set_backlight(dev, max * bclp / 255);
 
 	return 0;
 }
@@ -243,36 +223,6 @@ void opregion_asle_intr(struct drm_device *dev)
 	asle->aslc = asle_stat;
 }
 
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 cpu_pwm_ctl, pch_pwm_ctl2;
-	u32 max_backlight, level;
-
-	if (!(bclp & ASLE_BCLP_VALID))
-		return ASLE_BACKLIGHT_FAILED;
-
-	bclp &= ASLE_BCLP_MSK;
-	if (bclp < 0 || bclp > 255)
-		return ASLE_BACKLIGHT_FAILED;
-
-	cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
-	pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-	/* get the max PWM frequency */
-	max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
-	/* calculate the expected PMW frequency */
-	level = (bclp * max_backlight) / 255;
-	/* reserve the high 16 bits */
-	cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
-	/* write the updated PWM frequency */
-	I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-	return 0;
-}
-
 void ironlake_opregion_gse_intr(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -296,7 +246,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev)
 	}
 
 	if (asle_req & ASLE_SET_BACKLIGHT)
-		asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
+		asle_stat |= asle_set_backlight(dev, asle->bclp);
 
 	if (asle_req & ASLE_SET_PFIT) {
 		DRM_DEBUG_DRIVER("Pfit is not supported\n");
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ad312ca..a0f870f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -201,6 +201,9 @@ extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
 extern void intel_lvds_init(struct drm_device *dev);
+extern u32 intel_lvds_get_max_backlight(struct drm_device *dev);
+extern u32 intel_lvds_get_backlight(struct drm_device *dev);
+extern void intel_lvds_set_backlight(struct drm_device *dev, int level);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index b819c10..0ab5891 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -39,6 +39,7 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 #include <linux/acpi.h>
+#include <linux/backlight.h>
 
 /* Private structure for the integrated LVDS support */
 struct intel_lvds {
@@ -54,42 +55,178 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
 }
 
 /**
- * Sets the backlight level.
- *
- * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
+ * Returns the maximum level of the backlight duty cycle field.
  */
-static void intel_lvds_set_backlight(struct drm_device *dev, int level)
+u32 intel_lvds_get_max_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 blc_pwm_ctl, reg;
+	u32 reg;
+	int value;
+	bool combo;
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_CPU_CTL;
+	if (IS_I965G(dev))
+		combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+	else
+		combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	if (IS_IRONLAKE(dev))
+		reg = BLC_PWM_PCH_CTL2;
 	else
 		reg = BLC_PWM_CTL;
 
-	blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-	I915_WRITE(reg, (blc_pwm_ctl |
-				 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+	value = ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+		 BACKLIGHT_MODULATION_FREQ_SHIFT);
+
+	if (!IS_PINEVIEW(dev))
+		value *= 2;
+
+	if (combo) {
+		value *= 0xff;
+		value /= 2;
+	}
+
+	return value;
 }
 
 /**
- * Returns the maximum level of the backlight duty cycle field.
+ * Returns the level of the backlight duty cycle field.
  */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+u32 intel_lvds_get_backlight(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 reg;
+	u8 lbpc;
+	int value;
+	bool combo;
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_PCH_CTL2;
+	if (IS_I965G(dev))
+		combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+	else
+		combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	if (IS_IRONLAKE(dev))
+		reg = BLC_PWM_CPU_CTL;
+	else
+		reg = BLC_PWM_CTL;
+
+	value = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK;
+
+	if (IS_PINEVIEW(dev))
+		value /= 2;
+
+	if (combo) {
+		value &= ~0x1;
+		pci_read_config_byte(dev->pdev, LBB, &lbpc);
+		value *= lbpc;
+		value /= 2;
+	}
+
+	return value;
+}
+
+/**
+ * Sets the backlight level.
+  *
+  * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
+  */
+void intel_lvds_set_backlight(struct drm_device *dev, int level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 blc_pwm_ctl, reg;
+	bool combo;
+	u8 lbpc;
+
+	if (IS_I965G(dev))
+		combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+	else
+		combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	if (IS_IRONLAKE(dev))
+		reg = BLC_PWM_CPU_CTL;
 	else
 		reg = BLC_PWM_CTL;
 
-	return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
-		BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+	if (combo) {
+		int maximum = intel_lvds_get_max_backlight(dev);
+		lbpc = level * 0xfe / maximum;
+		lbpc += 1;
+		pci_write_config_byte(dev->pdev, LBB, lbpc);
+		level /= lbpc;
+		level <<= 1;
+	}
+
+	if (IS_PINEVIEW(dev)) {
+		blc_pwm_ctl = I915_READ(reg) & ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+		I915_WRITE(reg, (blc_pwm_ctl |
+			 (level << (BACKLIGHT_DUTY_CYCLE_SHIFT + 1))));
+	} else {
+		blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+		I915_WRITE(reg, blc_pwm_ctl |
+		   (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
+	}
 }
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_lvds_update_status(struct backlight_device *bd)
+{
+	struct drm_device *dev = bl_get_data(bd);
+	intel_lvds_set_backlight(dev, bd->props.brightness);
+	return 0;
+}
+
+static int intel_lvds_get_brightness(struct backlight_device *bd)
+{
+	struct drm_device *dev = bl_get_data(bd);
+	return intel_lvds_get_backlight(dev);
+}
+
+static const struct backlight_ops intel_lvds_bl_ops = {
+	.update_status = intel_lvds_update_status,
+	.get_brightness = intel_lvds_get_brightness,
+};
+
+static int intel_lvds_backlight_setup(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct backlight_properties props;
+
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = intel_lvds_get_max_backlight(dev);
+	dev_priv->backlight =
+		backlight_device_register("intel_backlight",
+					  &dev_priv->int_lvds_connector->kdev,
+					  dev,
+					  &intel_lvds_bl_ops,
+					  &props);
+
+	if (IS_ERR(dev_priv->backlight)) {
+		DRM_ERROR("Failed to register backlight: %ld\n",
+			  PTR_ERR(dev_priv->backlight));
+		dev_priv->backlight = NULL;
+		return -ENODEV;
+	}
+	dev_priv->backlight->props.brightness = intel_lvds_get_backlight(dev);
+	return 0;
+}
+
+static void intel_lvds_backlight_destroy(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (dev_priv->backlight)
+		backlight_device_unregister(dev_priv->backlight);
+}
+#else
+static int intel_lvds_backlight_setup(struct drm_device *dev)
+{
+	return 0;
+}
+
+static void intel_lvds_backlight_destroy(struct drm_device *dev)
+{
+	return;
+}
+#endif
+
 /**
  * Sets the power state for the panel.
  */
@@ -394,8 +531,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
 		reg = BLC_PWM_CTL;
 
 	dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
-	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-				       BACKLIGHT_DUTY_CYCLE_MASK);
+	dev_priv->backlight_duty_cycle = intel_lvds_get_backlight(dev);
 
 	intel_lvds_set_power(dev, false);
 }
@@ -573,6 +709,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	intel_lvds_backlight_destroy(dev);
+
 	if (dev_priv->lid_notifier.notifier_call)
 		acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
 	drm_sysfs_connector_remove(connector);
@@ -992,6 +1130,9 @@ out:
 	/* keep the LVDS connector */
 	dev_priv->int_lvds_connector = connector;
 	drm_sysfs_connector_add(connector);
+
+	intel_lvds_backlight_setup(dev);
+
 	return;
 
 failed:
-- 
1.7.2.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
  2010-09-08 16:32 ` Matthew Garrett
  (?)
  (?)
@ 2010-09-08 16:32 ` Matthew Garrett
  2010-09-08 16:58   ` Alex Deucher
  2010-09-13  7:54     ` Michel Dänzer
  -1 siblings, 2 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 16:32 UTC (permalink / raw)
  To: linux-kernel
  Cc: Michel Dänzer, Michel Dänzer, Matthew Garrett, dri-devel

From: Michel Dänzer <michel@daenzer.net>

Allows e.g. power management daemons to control the backlight level. Inspired
by the corresponding code in radeonfb.

(Updated to add backlight type and make the connector the parent device - mjg)

Signed-off-by: Michel Dänzer <daenzer@vmware.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Cc: dri-devel@lists.freedesktop.org
---
 drivers/gpu/drm/radeon/Kconfig                  |    1 +
 drivers/gpu/drm/radeon/radeon_legacy_encoders.c |  257 ++++++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_mode.h            |   10 +
 3 files changed, 262 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 1c02d23..9746fee 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -1,6 +1,7 @@
 config DRM_RADEON_KMS
 	bool "Enable modesetting on radeon by default - NEW DRIVER"
 	depends on DRM_RADEON
+	select BACKLIGHT_CLASS_DEVICE
 	help
 	  Choose this option if you want kernel modesetting enabled by default.
 
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 0b83970..e873935 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -28,6 +28,7 @@
 #include "radeon_drm.h"
 #include "radeon.h"
 #include "atom.h"
+#include <linux/backlight.h>
 
 static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 {
@@ -39,7 +40,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 	radeon_encoder->active_device = 0;
 }
 
-static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -47,15 +48,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 	uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
 	int panel_pwr_delay = 2000;
 	bool is_mac = false;
+	uint8_t backlight_level;
 	DRM_DEBUG_KMS("\n");
 
+	lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+	backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
 	if (radeon_encoder->enc_priv) {
 		if (rdev->is_atom_bios) {
 			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
 			panel_pwr_delay = lvds->panel_pwr_delay;
+			if (lvds->bl_dev)
+				backlight_level = lvds->backlight_level;
 		} else {
 			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
 			panel_pwr_delay = lvds->panel_pwr_delay;
+			if (lvds->bl_dev)
+				backlight_level = lvds->backlight_level;
 		}
 	}
 
@@ -82,11 +91,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 		lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
 		WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
 
-		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
-		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
+		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
+				   RADEON_LVDS_BL_MOD_LEVEL_MASK);
+		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
+				  RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
+				  (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
 		if (is_mac)
 			lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
-		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
 		udelay(panel_pwr_delay * 1000);
 		WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
 		break;
@@ -95,7 +106,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 	case DRM_MODE_DPMS_OFF:
 		pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
 		WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
-		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
 		lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
 		if (is_mac) {
 			lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
@@ -119,6 +129,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 
 }
 
+static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	DRM_DEBUG("\n");
+
+	if (radeon_encoder->enc_priv) {
+		if (rdev->is_atom_bios) {
+			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+			lvds->dpms_mode = mode;
+		} else {
+			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+			lvds->dpms_mode = mode;
+		}
+	}
+
+	radeon_legacy_lvds_update(encoder, mode);
+}
+
 static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
@@ -237,9 +266,224 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
 	.disable = radeon_legacy_encoder_disable,
 };
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+#define MAX_RADEON_LEVEL 0xFF
+
+struct radeon_backlight_privdata {
+	struct radeon_encoder *encoder;
+	uint8_t negative;
+};
+
+static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	uint8_t level;
+
+	/* Convert brightness to hardware level */
+	if (bd->props.brightness < 0)
+		level = 0;
+	else if (bd->props.brightness > MAX_RADEON_LEVEL)
+		level = MAX_RADEON_LEVEL;
+	else
+		level = bd->props.brightness;
+
+	if (pdata->negative)
+		level = MAX_RADEON_LEVEL - level;
+
+	return level;
+}
+
+static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	struct radeon_encoder *radeon_encoder = pdata->encoder;
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	int dpms_mode = DRM_MODE_DPMS_ON;
+
+	if (radeon_encoder->enc_priv) {
+		if (rdev->is_atom_bios) {
+			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+			dpms_mode = lvds->dpms_mode;
+			lvds->backlight_level = radeon_legacy_lvds_level(bd);
+		} else {
+			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+			dpms_mode = lvds->dpms_mode;
+			lvds->backlight_level = radeon_legacy_lvds_level(bd);
+		}
+	}
+
+	if (bd->props.brightness > 0)
+		radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
+	else
+		radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF);
+
+	return 0;
+}
+
+static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	struct radeon_encoder *radeon_encoder = pdata->encoder;
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	uint8_t backlight_level;
+
+	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+	return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level;
+}
+
+static const struct backlight_ops radeon_backlight_ops = {
+	.get_brightness = radeon_legacy_backlight_get_brightness,
+	.update_status	= radeon_legacy_backlight_update_status,
+};
+
+static void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder)
+{
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct backlight_device *bd;
+	struct backlight_properties props;
+	struct radeon_backlight_privdata *pdata;
+	struct drm_connector *connector;
+	uint8_t backlight_level;
+
+	if (!radeon_encoder->enc_priv)
+		return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!pmac_has_backlight_type("ati") &&
+	    !pmac_has_backlight_type("mnca"))
+		return;
+#endif
+
+	pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
+	if (!pdata) {
+		DRM_ERROR("Memory allocation failed\n");
+		goto error;
+	}
+
+	connector = radeon_get_connector_for_encoder(&radeon_encoder->base);
+
+	props.max_brightness = MAX_RADEON_LEVEL;
+	props.type = BACKLIGHT_RAW;
+	bd = backlight_device_register("radeon_backlight", &connector->kdev,
+				       pdata, &radeon_backlight_ops, &props);
+	if (IS_ERR(bd)) {
+		DRM_ERROR("Backlight registration failed\n");
+		goto error;
+	}
+
+	pdata->encoder = radeon_encoder;
+
+	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+	/* First, try to detect backlight level sense based on the assumption
+	 * that firmware set it up at full brightness
+	 */
+	if (backlight_level == 0)
+		pdata->negative = true;
+	else if (backlight_level == 0xff)
+		pdata->negative = false;
+	else {
+		/* XXX hack... maybe some day we can figure out in what direction
+		 * backlight should work on a given panel?
+		 */
+		pdata->negative = (rdev->family != CHIP_RV200 &&
+				   rdev->family != CHIP_RV250 &&
+				   rdev->family != CHIP_RV280 &&
+				   rdev->family != CHIP_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+		pdata->negative = (pdata->negative ||
+				   machine_is_compatible("PowerBook4,3") ||
+				   machine_is_compatible("PowerBook6,3") ||
+				   machine_is_compatible("PowerBook6,5"));
+#endif
+	}
+
+	if (rdev->is_atom_bios) {
+		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+		lvds->bl_dev = bd;
+	} else {
+		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+		lvds->bl_dev = bd;
+	}
+
+	bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
+	bd->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(bd);
+
+	DRM_INFO("radeon legacy LVDS backlight initialized\n");
+
+	return;
+
+error:
+	kfree(pdata);
+	return;
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
+{
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct backlight_device *bd = NULL;
+
+	if (!radeon_encoder->enc_priv)
+		return;
+
+	if (rdev->is_atom_bios) {
+		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+		bd = lvds->bl_dev;
+		lvds->bl_dev = NULL;
+	} else {
+		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+		bd = lvds->bl_dev;
+		lvds->bl_dev = NULL;
+	}
+
+	if (bd) {
+		struct radeon_legacy_backlight_privdata *pdata;
+
+		pdata = bl_get_data(bd);
+		backlight_device_unregister(bd);
+		kfree(pdata);
+
+		DRM_INFO("radeon legacy LVDS backlight unloaded\n");
+	}
+}
+
+#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+static void radeon_legacy_backlight_init(struct radeon_encoder *encoder)
+{
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder)
+{
+}
+
+#endif
+
+
+static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->enc_priv) {
+		radeon_legacy_backlight_exit(radeon_encoder);
+		kfree(radeon_encoder->enc_priv);
+	}
+	drm_encoder_cleanup(encoder);
+	kfree(radeon_encoder);
+}
 
 static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
-	.destroy = radeon_enc_destroy,
+	.destroy = radeon_lvds_enc_destroy,
 };
 
 static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
@@ -1389,6 +1633,7 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_
 		else
 			radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder);
 		radeon_encoder->rmx_type = RMX_FULL;
+		radeon_legacy_backlight_init(radeon_encoder);
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
 		drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index efbe975..dc5f51c 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -302,6 +302,11 @@ struct radeon_encoder_lvds {
 	uint32_t lvds_gen_cntl;
 	/* panel mode */
 	struct drm_display_mode native_mode;
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	struct backlight_device *bl_dev;
+	int      dpms_mode;
+	uint8_t  backlight_level;
+#endif
 };
 
 struct radeon_encoder_tv_dac {
@@ -353,6 +358,11 @@ struct radeon_encoder_atom_dig {
 	struct radeon_atom_ss *ss;
 	/* panel mode */
 	struct drm_display_mode native_mode;
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	struct backlight_device *bl_dev;
+	int dpms_mode;
+	uint8_t backlight_level;
+#endif
 };
 
 struct radeon_encoder_atom_dac {
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
  2010-09-08 16:32 ` [PATCH] radeon: Expose backlight class device for legacy LVDS encoder Matthew Garrett
@ 2010-09-08 16:58   ` Alex Deucher
  2010-09-08 17:03       ` Matthew Garrett
  2010-09-13  7:54     ` Michel Dänzer
  1 sibling, 1 reply; 26+ messages in thread
From: Alex Deucher @ 2010-09-08 16:58 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: linux-kernel, Michel Dänzer, dri-devel, Michel Dänzer

On Wed, Sep 8, 2010 at 12:32 PM, Matthew Garrett <mjg@redhat.com> wrote:
> From: Michel Dänzer <michel@daenzer.net>
>
> Allows e.g. power management daemons to control the backlight level. Inspired
> by the corresponding code in radeonfb.
>

The only problem with this is that not all oems use the internal
backlight controller; systems that don't need to use the acpi methods.
 On atombios systems there is a bit in the
ATOM_FIRMWARE_CAPABILITY_ACCESS struct in the FirmwareInfo data table
to determine whether the backlight is controlled by the GPU or some
external mechanism.  Combios may have something similar.  If the
backlight is controlled via the GPU, it can be adjusting using the
atom OutputControl and TransmitterControl control tables depending on
the GPU family.  However, if the driver chooses to control the
backlight itself, it needs to set the appropriate bit in the bios
scratch regs to tell the firmware not to attempt to change the
backlight itself.

Alex

> (Updated to add backlight type and make the connector the parent device - mjg)
>
> Signed-off-by: Michel Dänzer <daenzer@vmware.com>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> Cc: dri-devel@lists.freedesktop.org
> ---
>  drivers/gpu/drm/radeon/Kconfig                  |    1 +
>  drivers/gpu/drm/radeon/radeon_legacy_encoders.c |  257 ++++++++++++++++++++++-
>  drivers/gpu/drm/radeon/radeon_mode.h            |   10 +
>  3 files changed, 262 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
> index 1c02d23..9746fee 100644
> --- a/drivers/gpu/drm/radeon/Kconfig
> +++ b/drivers/gpu/drm/radeon/Kconfig
> @@ -1,6 +1,7 @@
>  config DRM_RADEON_KMS
>        bool "Enable modesetting on radeon by default - NEW DRIVER"
>        depends on DRM_RADEON
> +       select BACKLIGHT_CLASS_DEVICE
>        help
>          Choose this option if you want kernel modesetting enabled by default.
>
> diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
> index 0b83970..e873935 100644
> --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
> +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
> @@ -28,6 +28,7 @@
>  #include "radeon_drm.h"
>  #include "radeon.h"
>  #include "atom.h"
> +#include <linux/backlight.h>
>
>  static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
>  {
> @@ -39,7 +40,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
>        radeon_encoder->active_device = 0;
>  }
>
> -static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
> +static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
>  {
>        struct drm_device *dev = encoder->dev;
>        struct radeon_device *rdev = dev->dev_private;
> @@ -47,15 +48,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
>        uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
>        int panel_pwr_delay = 2000;
>        bool is_mac = false;
> +       uint8_t backlight_level;
>        DRM_DEBUG_KMS("\n");
>
> +       lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
> +       backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
> +
>        if (radeon_encoder->enc_priv) {
>                if (rdev->is_atom_bios) {
>                        struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
>                        panel_pwr_delay = lvds->panel_pwr_delay;
> +                       if (lvds->bl_dev)
> +                               backlight_level = lvds->backlight_level;
>                } else {
>                        struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
>                        panel_pwr_delay = lvds->panel_pwr_delay;
> +                       if (lvds->bl_dev)
> +                               backlight_level = lvds->backlight_level;
>                }
>        }
>
> @@ -82,11 +91,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
>                lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
>                WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
>
> -               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
> -               lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
> +               lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
> +                                  RADEON_LVDS_BL_MOD_LEVEL_MASK);
> +               lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
> +                                 RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
> +                                 (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
>                if (is_mac)
>                        lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
> -               lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
>                udelay(panel_pwr_delay * 1000);
>                WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
>                break;
> @@ -95,7 +106,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
>        case DRM_MODE_DPMS_OFF:
>                pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
>                WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
> -               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
>                lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
>                if (is_mac) {
>                        lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
> @@ -119,6 +129,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
>
>  }
>
> +static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
> +{
> +       struct radeon_device *rdev = encoder->dev->dev_private;
> +       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
> +       DRM_DEBUG("\n");
> +
> +       if (radeon_encoder->enc_priv) {
> +               if (rdev->is_atom_bios) {
> +                       struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
> +                       lvds->dpms_mode = mode;
> +               } else {
> +                       struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
> +                       lvds->dpms_mode = mode;
> +               }
> +       }
> +
> +       radeon_legacy_lvds_update(encoder, mode);
> +}
> +
>  static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
>  {
>        struct radeon_device *rdev = encoder->dev->dev_private;
> @@ -237,9 +266,224 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
>        .disable = radeon_legacy_encoder_disable,
>  };
>
> +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
> +
> +#define MAX_RADEON_LEVEL 0xFF
> +
> +struct radeon_backlight_privdata {
> +       struct radeon_encoder *encoder;
> +       uint8_t negative;
> +};
> +
> +static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
> +{
> +       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
> +       uint8_t level;
> +
> +       /* Convert brightness to hardware level */
> +       if (bd->props.brightness < 0)
> +               level = 0;
> +       else if (bd->props.brightness > MAX_RADEON_LEVEL)
> +               level = MAX_RADEON_LEVEL;
> +       else
> +               level = bd->props.brightness;
> +
> +       if (pdata->negative)
> +               level = MAX_RADEON_LEVEL - level;
> +
> +       return level;
> +}
> +
> +static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
> +{
> +       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
> +       struct radeon_encoder *radeon_encoder = pdata->encoder;
> +       struct drm_device *dev = radeon_encoder->base.dev;
> +       struct radeon_device *rdev = dev->dev_private;
> +       int dpms_mode = DRM_MODE_DPMS_ON;
> +
> +       if (radeon_encoder->enc_priv) {
> +               if (rdev->is_atom_bios) {
> +                       struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
> +                       dpms_mode = lvds->dpms_mode;
> +                       lvds->backlight_level = radeon_legacy_lvds_level(bd);
> +               } else {
> +                       struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
> +                       dpms_mode = lvds->dpms_mode;
> +                       lvds->backlight_level = radeon_legacy_lvds_level(bd);
> +               }
> +       }
> +
> +       if (bd->props.brightness > 0)
> +               radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
> +       else
> +               radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF);
> +
> +       return 0;
> +}
> +
> +static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
> +{
> +       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
> +       struct radeon_encoder *radeon_encoder = pdata->encoder;
> +       struct drm_device *dev = radeon_encoder->base.dev;
> +       struct radeon_device *rdev = dev->dev_private;
> +       uint8_t backlight_level;
> +
> +       backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
> +                          RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
> +
> +       return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level;
> +}
> +
> +static const struct backlight_ops radeon_backlight_ops = {
> +       .get_brightness = radeon_legacy_backlight_get_brightness,
> +       .update_status  = radeon_legacy_backlight_update_status,
> +};
> +
> +static void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder)
> +{
> +       struct drm_device *dev = radeon_encoder->base.dev;
> +       struct radeon_device *rdev = dev->dev_private;
> +       struct backlight_device *bd;
> +       struct backlight_properties props;
> +       struct radeon_backlight_privdata *pdata;
> +       struct drm_connector *connector;
> +       uint8_t backlight_level;
> +
> +       if (!radeon_encoder->enc_priv)
> +               return;
> +
> +#ifdef CONFIG_PMAC_BACKLIGHT
> +       if (!pmac_has_backlight_type("ati") &&
> +           !pmac_has_backlight_type("mnca"))
> +               return;
> +#endif
> +
> +       pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
> +       if (!pdata) {
> +               DRM_ERROR("Memory allocation failed\n");
> +               goto error;
> +       }
> +
> +       connector = radeon_get_connector_for_encoder(&radeon_encoder->base);
> +
> +       props.max_brightness = MAX_RADEON_LEVEL;
> +       props.type = BACKLIGHT_RAW;
> +       bd = backlight_device_register("radeon_backlight", &connector->kdev,
> +                                      pdata, &radeon_backlight_ops, &props);
> +       if (IS_ERR(bd)) {
> +               DRM_ERROR("Backlight registration failed\n");
> +               goto error;
> +       }
> +
> +       pdata->encoder = radeon_encoder;
> +
> +       backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
> +                          RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
> +
> +       /* First, try to detect backlight level sense based on the assumption
> +        * that firmware set it up at full brightness
> +        */
> +       if (backlight_level == 0)
> +               pdata->negative = true;
> +       else if (backlight_level == 0xff)
> +               pdata->negative = false;
> +       else {
> +               /* XXX hack... maybe some day we can figure out in what direction
> +                * backlight should work on a given panel?
> +                */
> +               pdata->negative = (rdev->family != CHIP_RV200 &&
> +                                  rdev->family != CHIP_RV250 &&
> +                                  rdev->family != CHIP_RV280 &&
> +                                  rdev->family != CHIP_RV350);
> +
> +#ifdef CONFIG_PMAC_BACKLIGHT
> +               pdata->negative = (pdata->negative ||
> +                                  machine_is_compatible("PowerBook4,3") ||
> +                                  machine_is_compatible("PowerBook6,3") ||
> +                                  machine_is_compatible("PowerBook6,5"));
> +#endif
> +       }
> +
> +       if (rdev->is_atom_bios) {
> +               struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
> +               lvds->bl_dev = bd;
> +       } else {
> +               struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
> +               lvds->bl_dev = bd;
> +       }
> +
> +       bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
> +       bd->props.power = FB_BLANK_UNBLANK;
> +       backlight_update_status(bd);
> +
> +       DRM_INFO("radeon legacy LVDS backlight initialized\n");
> +
> +       return;
> +
> +error:
> +       kfree(pdata);
> +       return;
> +}
> +
> +static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
> +{
> +       struct drm_device *dev = radeon_encoder->base.dev;
> +       struct radeon_device *rdev = dev->dev_private;
> +       struct backlight_device *bd = NULL;
> +
> +       if (!radeon_encoder->enc_priv)
> +               return;
> +
> +       if (rdev->is_atom_bios) {
> +               struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
> +               bd = lvds->bl_dev;
> +               lvds->bl_dev = NULL;
> +       } else {
> +               struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
> +               bd = lvds->bl_dev;
> +               lvds->bl_dev = NULL;
> +       }
> +
> +       if (bd) {
> +               struct radeon_legacy_backlight_privdata *pdata;
> +
> +               pdata = bl_get_data(bd);
> +               backlight_device_unregister(bd);
> +               kfree(pdata);
> +
> +               DRM_INFO("radeon legacy LVDS backlight unloaded\n");
> +       }
> +}
> +
> +#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
> +
> +static void radeon_legacy_backlight_init(struct radeon_encoder *encoder)
> +{
> +}
> +
> +static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder)
> +{
> +}
> +
> +#endif
> +
> +
> +static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
> +{
> +       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
> +
> +       if (radeon_encoder->enc_priv) {
> +               radeon_legacy_backlight_exit(radeon_encoder);
> +               kfree(radeon_encoder->enc_priv);
> +       }
> +       drm_encoder_cleanup(encoder);
> +       kfree(radeon_encoder);
> +}
>
>  static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
> -       .destroy = radeon_enc_destroy,
> +       .destroy = radeon_lvds_enc_destroy,
>  };
>
>  static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
> @@ -1389,6 +1633,7 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_
>                else
>                        radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder);
>                radeon_encoder->rmx_type = RMX_FULL;
> +               radeon_legacy_backlight_init(radeon_encoder);
>                break;
>        case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
>                drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS);
> diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
> index efbe975..dc5f51c 100644
> --- a/drivers/gpu/drm/radeon/radeon_mode.h
> +++ b/drivers/gpu/drm/radeon/radeon_mode.h
> @@ -302,6 +302,11 @@ struct radeon_encoder_lvds {
>        uint32_t lvds_gen_cntl;
>        /* panel mode */
>        struct drm_display_mode native_mode;
> +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
> +       struct backlight_device *bl_dev;
> +       int      dpms_mode;
> +       uint8_t  backlight_level;
> +#endif
>  };
>
>  struct radeon_encoder_tv_dac {
> @@ -353,6 +358,11 @@ struct radeon_encoder_atom_dig {
>        struct radeon_atom_ss *ss;
>        /* panel mode */
>        struct drm_display_mode native_mode;
> +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
> +       struct backlight_device *bl_dev;
> +       int dpms_mode;
> +       uint8_t backlight_level;
> +#endif
>  };
>
>  struct radeon_encoder_atom_dac {
> --
> 1.7.2.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
  2010-09-08 16:58   ` Alex Deucher
@ 2010-09-08 17:03       ` Matthew Garrett
  0 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 17:03 UTC (permalink / raw)
  To: Alex Deucher
  Cc: linux-kernel, Michel Dänzer, dri-devel, Michel Dänzer

On Wed, Sep 08, 2010 at 12:58:32PM -0400, Alex Deucher wrote:

> The only problem with this is that not all oems use the internal
> backlight controller; systems that don't need to use the acpi methods.

That's why we expose the backlight type. Userspace should use the acpi 
or platform mechanism when available, with this being a last-ditch 
fallback.

>  On atombios systems there is a bit in the
> ATOM_FIRMWARE_CAPABILITY_ACCESS struct in the FirmwareInfo data table
> to determine whether the backlight is controlled by the GPU or some
> external mechanism.  Combios may have something similar.  If the
> backlight is controlled via the GPU, it can be adjusting using the
> atom OutputControl and TransmitterControl control tables depending on
> the GPU family.  However, if the driver chooses to control the
> backlight itself, it needs to set the appropriate bit in the bios
> scratch regs to tell the firmware not to attempt to change the
> backlight itself.

If there's support for probing this more reliably then I'm all for that, 
but I'm not keen on taking over control if the BIOS has previous 
asserted it.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
@ 2010-09-08 17:03       ` Matthew Garrett
  0 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-08 17:03 UTC (permalink / raw)
  To: Alex Deucher
  Cc: Michel Dänzer, Michel Dänzer, linux-kernel, dri-devel

On Wed, Sep 08, 2010 at 12:58:32PM -0400, Alex Deucher wrote:

> The only problem with this is that not all oems use the internal
> backlight controller; systems that don't need to use the acpi methods.

That's why we expose the backlight type. Userspace should use the acpi 
or platform mechanism when available, with this being a last-ditch 
fallback.

>  On atombios systems there is a bit in the
> ATOM_FIRMWARE_CAPABILITY_ACCESS struct in the FirmwareInfo data table
> to determine whether the backlight is controlled by the GPU or some
> external mechanism.  Combios may have something similar.  If the
> backlight is controlled via the GPU, it can be adjusting using the
> atom OutputControl and TransmitterControl control tables depending on
> the GPU family.  However, if the driver chooses to control the
> backlight itself, it needs to set the appropriate bit in the bios
> scratch regs to tell the firmware not to attempt to change the
> backlight itself.

If there's support for probing this more reliably then I'm all for that, 
but I'm not keen on taking over control if the BIOS has previous 
asserted it.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
  2010-09-08 17:03       ` Matthew Garrett
  (?)
@ 2010-09-08 17:04       ` Alex Deucher
  -1 siblings, 0 replies; 26+ messages in thread
From: Alex Deucher @ 2010-09-08 17:04 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: linux-kernel, Michel Dänzer, dri-devel, Michel Dänzer

On Wed, Sep 8, 2010 at 1:03 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> On Wed, Sep 08, 2010 at 12:58:32PM -0400, Alex Deucher wrote:
>
>> The only problem with this is that not all oems use the internal
>> backlight controller; systems that don't need to use the acpi methods.
>
> That's why we expose the backlight type. Userspace should use the acpi
> or platform mechanism when available, with this being a last-ditch
> fallback.

Ah, gotcha.

>
>>  On atombios systems there is a bit in the
>> ATOM_FIRMWARE_CAPABILITY_ACCESS struct in the FirmwareInfo data table
>> to determine whether the backlight is controlled by the GPU or some
>> external mechanism.  Combios may have something similar.  If the
>> backlight is controlled via the GPU, it can be adjusting using the
>> atom OutputControl and TransmitterControl control tables depending on
>> the GPU family.  However, if the driver chooses to control the
>> backlight itself, it needs to set the appropriate bit in the bios
>> scratch regs to tell the firmware not to attempt to change the
>> backlight itself.
>
> If there's support for probing this more reliably then I'm all for that,
> but I'm not keen on taking over control if the BIOS has previous
> asserted it.

Agreed.

Alex

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] Backlight: Add backlight type
  2010-09-08 16:32 ` Matthew Garrett
                   ` (2 preceding siblings ...)
  (?)
@ 2010-09-09 16:59 ` Mike Frysinger
  -1 siblings, 0 replies; 26+ messages in thread
From: Mike Frysinger @ 2010-09-09 16:59 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, Richard Purdie, intel-gfx, dri-devel

On Wed, Sep 8, 2010 at 12:32, Matthew Garrett <mjg@redhat.com> wrote:
> There may be multiple ways of controlling the backlight on a given machine.
> Allow drivers to expose the type of interface they are providing, making
> it possible for userspace to make appropriate policy decisions.

maybe i missed something, but i dont see the core validating the .type
value at registration time.  since the value is then used later as an
index into an array, shouldnt it verify that it is valid ?

do you want to force everyone to declare they're "raw" ?  or just go
with the memset default to have people start with "raw" ?  otherwise
it might make sense to have the first enum be BACKLIGHT_UNKNOWN and
have the core warn when it hits that.

> --- a/drivers/video/backlight/backlight.c
> +++ b/drivers/video/backlight/backlight.c
>
> +static const char *backlight_types[] = {
> +       [BACKLIGHT_RAW] = "raw",
> +       [BACKLIGHT_PLATFORM] = "platform",
> +       [BACKLIGHT_FIRMWARE] = "firmware",
> +};

const char * const backlight_types[] ?
-mke

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Intel-gfx] [PATCH] i915: Add native backlight control
  2010-09-08 16:32   ` Matthew Garrett
@ 2010-09-09 17:09     ` Chris Wilson
  -1 siblings, 0 replies; 26+ messages in thread
From: Chris Wilson @ 2010-09-09 17:09 UTC (permalink / raw)
  To: Matthew Garrett, linux-kernel; +Cc: intel-gfx, Matthew Garrett

On Wed,  8 Sep 2010 12:32:18 -0400, Matthew Garrett <mjg@redhat.com> wrote:
> Not all systems expose a firmware or platform mechanism for changing the
> backlight intensity on i915, so add native driver support.

This will conflict with a similar patch I have in drm-intel-next to unify
the various bits of code that were attempting to modify the BLC PWM, each
in their own unique fashion.

I'll respin this native interface on top of that. Do you want to add a
native RAW interface all in one go, or to base it on the current
backlight_device and then to add the RAW property with this patch set?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] i915: Add native backlight control
@ 2010-09-09 17:09     ` Chris Wilson
  0 siblings, 0 replies; 26+ messages in thread
From: Chris Wilson @ 2010-09-09 17:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: intel-gfx, Matthew Garrett

On Wed,  8 Sep 2010 12:32:18 -0400, Matthew Garrett <mjg@redhat.com> wrote:
> Not all systems expose a firmware or platform mechanism for changing the
> backlight intensity on i915, so add native driver support.

This will conflict with a similar patch I have in drm-intel-next to unify
the various bits of code that were attempting to modify the BLC PWM, each
in their own unique fashion.

I'll respin this native interface on top of that. Do you want to add a
native RAW interface all in one go, or to base it on the current
backlight_device and then to add the RAW property with this patch set?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Intel-gfx] [PATCH] i915: Add native backlight control
  2010-09-09 17:09     ` Chris Wilson
  (?)
@ 2010-09-09 17:14     ` Matthew Garrett
  -1 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-09 17:14 UTC (permalink / raw)
  To: Chris Wilson; +Cc: linux-kernel, intel-gfx

On Thu, Sep 09, 2010 at 06:09:40PM +0100, Chris Wilson wrote:
> On Wed,  8 Sep 2010 12:32:18 -0400, Matthew Garrett <mjg@redhat.com> wrote:
> > Not all systems expose a firmware or platform mechanism for changing the
> > backlight intensity on i915, so add native driver support.
> 
> This will conflict with a similar patch I have in drm-intel-next to unify
> the various bits of code that were attempting to modify the BLC PWM, each
> in their own unique fashion.
> 
> I'll respin this native interface on top of that. Do you want to add a
> native RAW interface all in one go, or to base it on the current
> backlight_device and then to add the RAW property with this patch set?

I don't think providing a native interface in i915 is beneficial without 
providing the type information - userspace just doesn't have any way to 
identify the correct device otherwise.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH] drm/i915: Expose a native backlight device
  2010-09-08 16:32   ` Matthew Garrett
@ 2010-09-10 13:38     ` Chris Wilson
  -1 siblings, 0 replies; 26+ messages in thread
From: Chris Wilson @ 2010-09-10 13:38 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, intel-gfx, Chris Wilson, Matthew Garrett

Based on an original patch by Matthew Garrett <mjg@redhat.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Matthew Garrett <mjg@redhat.com>
---
 drivers/gpu/drm/i915/intel_dp.c    |    7 ++++-
 drivers/gpu/drm/i915/intel_drv.h   |   19 +++++++++++++
 drivers/gpu/drm/i915/intel_lvds.c  |    4 +++
 drivers/gpu/drm/i915/intel_panel.c |   50 ++++++++++++++++++++++++++++++++++++
 4 files changed, 79 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index b9efeaf..537375d 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1522,8 +1522,10 @@ static int intel_dp_get_modes(struct drm_connector *connector)
 }
 
 static void
-intel_dp_destroy (struct drm_connector *connector)
+intel_dp_destroy(struct drm_connector *connector)
 {
+	intel_panel_backlight_destroy(to_intel_connector(connector));
+
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
 	kfree(connector);
@@ -1729,4 +1731,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
+
+	if (IS_eDP(intel_dp))
+	    intel_panel_backlight_create(intel_connector);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1ada684..5b6f9f7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/backlight.h>
 #include "i915_drv.h"
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
@@ -151,6 +152,9 @@ struct intel_encoder {
 struct intel_connector {
 	struct drm_connector base;
 	struct intel_encoder *encoder;
+
+	/* expose a RAW native backlight interface */
+	struct backlight_device *backlight;
 };
 
 struct intel_crtc {
@@ -229,6 +233,21 @@ extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+extern int intel_panel_backlight_create(struct intel_connector *connector);
+extern void intel_panel_backlight_destroy(struct intel_connector *connector);
+#else
+static inline int intel_panel_backlight_create(struct intel_connector *connector)
+{
+	return -ENODEV;
+}
+
+static inline void intel_panel_backlight_destroy(struct intel_connector *connector)
+{
+	return;
+}
+#endif
+
 extern int intel_panel_fitter_pipe (struct drm_device *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 93a711d..65d3e66 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -541,6 +541,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	intel_panel_backlight_destroy(to_intel_connector(connector));
+
 	if (dev_priv->lid_notifier.notifier_call)
 		acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
 	drm_sysfs_connector_remove(connector);
@@ -964,6 +966,8 @@ out:
 	/* keep the LVDS connector */
 	dev_priv->int_lvds_connector = connector;
 	drm_sysfs_connector_add(connector);
+
+	intel_panel_backlight_create(intel_connector);
 	return;
 
 failed:
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 30abe7a..ec7d38e 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -218,3 +218,53 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
 		tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
 	I915_WRITE(BLC_PWM_CTL, tmp | level);
 }
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_backlight_update_status(struct backlight_device *bd)
+{
+	struct intel_connector *connector = bl_get_data(bd);
+	intel_panel_set_backlight(connector->base.dev, bd->props.brightness);
+	return 0;
+}
+
+static int intel_backlight_get_brightness(struct backlight_device *bd)
+{
+	struct intel_connector *connector = bl_get_data(bd);
+	return intel_panel_get_backlight(connector->base.dev);
+}
+
+static const struct backlight_ops intel_backlight_ops = {
+	.update_status = intel_backlight_update_status,
+	.get_brightness = intel_backlight_get_brightness,
+};
+
+int intel_panel_backlight_create(struct intel_connector *connector)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct backlight_properties props;
+
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = intel_panel_get_max_backlight(dev);
+	connector->backlight =
+		backlight_device_register("intel_backlight",
+					  &connector->base.kdev,
+					  connector,
+					  &intel_backlight_ops,
+					  &props);
+	if (IS_ERR(connector->backlight)) {
+		int ret = PTR_ERR(connector->backlight);
+		DRM_ERROR("Failed to register backlight: %d\n", ret);
+		connector->backlight = NULL;
+		return ret;
+	}
+
+	connector->backlight->props.brightness = intel_panel_get_backlight(dev);
+	return 0;
+}
+
+void intel_panel_backlight_destroy(struct intel_connector *connector)
+{
+	if (connector->backlight)
+		backlight_device_unregister(connector->backlight);
+}
+#endif
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH] drm/i915: Expose a native backlight device
@ 2010-09-10 13:38     ` Chris Wilson
  0 siblings, 0 replies; 26+ messages in thread
From: Chris Wilson @ 2010-09-10 13:38 UTC (permalink / raw)
  Cc: intel-gfx, Matthew Garrett, linux-kernel

Based on an original patch by Matthew Garrett <mjg@redhat.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Matthew Garrett <mjg@redhat.com>
---
 drivers/gpu/drm/i915/intel_dp.c    |    7 ++++-
 drivers/gpu/drm/i915/intel_drv.h   |   19 +++++++++++++
 drivers/gpu/drm/i915/intel_lvds.c  |    4 +++
 drivers/gpu/drm/i915/intel_panel.c |   50 ++++++++++++++++++++++++++++++++++++
 4 files changed, 79 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index b9efeaf..537375d 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1522,8 +1522,10 @@ static int intel_dp_get_modes(struct drm_connector *connector)
 }
 
 static void
-intel_dp_destroy (struct drm_connector *connector)
+intel_dp_destroy(struct drm_connector *connector)
 {
+	intel_panel_backlight_destroy(to_intel_connector(connector));
+
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
 	kfree(connector);
@@ -1729,4 +1731,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
+
+	if (IS_eDP(intel_dp))
+	    intel_panel_backlight_create(intel_connector);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1ada684..5b6f9f7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/backlight.h>
 #include "i915_drv.h"
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
@@ -151,6 +152,9 @@ struct intel_encoder {
 struct intel_connector {
 	struct drm_connector base;
 	struct intel_encoder *encoder;
+
+	/* expose a RAW native backlight interface */
+	struct backlight_device *backlight;
 };
 
 struct intel_crtc {
@@ -229,6 +233,21 @@ extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+extern int intel_panel_backlight_create(struct intel_connector *connector);
+extern void intel_panel_backlight_destroy(struct intel_connector *connector);
+#else
+static inline int intel_panel_backlight_create(struct intel_connector *connector)
+{
+	return -ENODEV;
+}
+
+static inline void intel_panel_backlight_destroy(struct intel_connector *connector)
+{
+	return;
+}
+#endif
+
 extern int intel_panel_fitter_pipe (struct drm_device *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 93a711d..65d3e66 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -541,6 +541,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	intel_panel_backlight_destroy(to_intel_connector(connector));
+
 	if (dev_priv->lid_notifier.notifier_call)
 		acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
 	drm_sysfs_connector_remove(connector);
@@ -964,6 +966,8 @@ out:
 	/* keep the LVDS connector */
 	dev_priv->int_lvds_connector = connector;
 	drm_sysfs_connector_add(connector);
+
+	intel_panel_backlight_create(intel_connector);
 	return;
 
 failed:
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 30abe7a..ec7d38e 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -218,3 +218,53 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
 		tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
 	I915_WRITE(BLC_PWM_CTL, tmp | level);
 }
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_backlight_update_status(struct backlight_device *bd)
+{
+	struct intel_connector *connector = bl_get_data(bd);
+	intel_panel_set_backlight(connector->base.dev, bd->props.brightness);
+	return 0;
+}
+
+static int intel_backlight_get_brightness(struct backlight_device *bd)
+{
+	struct intel_connector *connector = bl_get_data(bd);
+	return intel_panel_get_backlight(connector->base.dev);
+}
+
+static const struct backlight_ops intel_backlight_ops = {
+	.update_status = intel_backlight_update_status,
+	.get_brightness = intel_backlight_get_brightness,
+};
+
+int intel_panel_backlight_create(struct intel_connector *connector)
+{
+	struct drm_device *dev = connector->base.dev;
+	struct backlight_properties props;
+
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = intel_panel_get_max_backlight(dev);
+	connector->backlight =
+		backlight_device_register("intel_backlight",
+					  &connector->base.kdev,
+					  connector,
+					  &intel_backlight_ops,
+					  &props);
+	if (IS_ERR(connector->backlight)) {
+		int ret = PTR_ERR(connector->backlight);
+		DRM_ERROR("Failed to register backlight: %d\n", ret);
+		connector->backlight = NULL;
+		return ret;
+	}
+
+	connector->backlight->props.brightness = intel_panel_get_backlight(dev);
+	return 0;
+}
+
+void intel_panel_backlight_destroy(struct intel_connector *connector)
+{
+	if (connector->backlight)
+		backlight_device_unregister(connector->backlight);
+}
+#endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] drm/i915: Expose a native backlight device
  2010-09-10 13:38     ` Chris Wilson
@ 2010-09-10 13:47       ` Matthew Garrett
  -1 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-10 13:47 UTC (permalink / raw)
  To: Chris Wilson; +Cc: linux-kernel, intel-gfx

On Fri, Sep 10, 2010 at 02:38:03PM +0100, Chris Wilson wrote:
> Based on an original patch by Matthew Garrett <mjg@redhat.com>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Matthew Garrett <mjg@redhat.com>

ACKed-by: Matthew Garrett <mjg@redhat.com>

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] drm/i915: Expose a native backlight device
@ 2010-09-10 13:47       ` Matthew Garrett
  0 siblings, 0 replies; 26+ messages in thread
From: Matthew Garrett @ 2010-09-10 13:47 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx, linux-kernel

On Fri, Sep 10, 2010 at 02:38:03PM +0100, Chris Wilson wrote:
> Based on an original patch by Matthew Garrett <mjg@redhat.com>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Matthew Garrett <mjg@redhat.com>

ACKed-by: Matthew Garrett <mjg@redhat.com>

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
  2010-09-08 16:32 ` [PATCH] radeon: Expose backlight class device for legacy LVDS encoder Matthew Garrett
@ 2010-09-13  7:54     ` Michel Dänzer
  2010-09-13  7:54     ` Michel Dänzer
  1 sibling, 0 replies; 26+ messages in thread
From: Michel Dänzer @ 2010-09-13  7:54 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, dri-devel

On Mit, 2010-09-08 at 12:32 -0400, Matthew Garrett wrote: 
> From: Michel Dänzer <michel@daenzer.net>
> 
> Allows e.g. power management daemons to control the backlight level. Inspired
> by the corresponding code in radeonfb.
> 
> (Updated to add backlight type and make the connector the parent device - mjg)
> 
> Signed-off-by: Michel Dänzer <daenzer@vmware.com>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>

Thanks for picking this up, Matthew.

Unfortunately, it fails to build here:

  CC [M]  drivers/gpu/drm/radeon/radeon_legacy_encoders.o
drivers/gpu/drm/radeon/radeon_legacy_encoders.c: In function ‘radeon_legacy_backlight_init’:
drivers/gpu/drm/radeon/radeon_legacy_encoders.c:358: error: implicit declaration of function ‘pmac_has_backlight_type’
drivers/gpu/drm/radeon/radeon_legacy_encoders.c:403: error: implicit declaration of function ‘machine_is_compatible’
make[1]: *** [drivers/gpu/drm/radeon/radeon_legacy_encoders.o] Error 1
make: *** [_module_drivers/gpu/drm/radeon] Error 2

Am I missing changes from another tree?


-- 
Earthling Michel Dänzer           |                http://www.vmware.com
Libre software enthusiast         |          Debian, X and DRI developer

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
@ 2010-09-13  7:54     ` Michel Dänzer
  0 siblings, 0 replies; 26+ messages in thread
From: Michel Dänzer @ 2010-09-13  7:54 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, dri-devel

On Mit, 2010-09-08 at 12:32 -0400, Matthew Garrett wrote: 
> From: Michel Dänzer <michel@daenzer.net>
> 
> Allows e.g. power management daemons to control the backlight level. Inspired
> by the corresponding code in radeonfb.
> 
> (Updated to add backlight type and make the connector the parent device - mjg)
> 
> Signed-off-by: Michel Dänzer <daenzer@vmware.com>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>

Thanks for picking this up, Matthew.

Unfortunately, it fails to build here:

  CC [M]  drivers/gpu/drm/radeon/radeon_legacy_encoders.o
drivers/gpu/drm/radeon/radeon_legacy_encoders.c: In function ‘radeon_legacy_backlight_init’:
drivers/gpu/drm/radeon/radeon_legacy_encoders.c:358: error: implicit declaration of function ‘pmac_has_backlight_type’
drivers/gpu/drm/radeon/radeon_legacy_encoders.c:403: error: implicit declaration of function ‘machine_is_compatible’
make[1]: *** [drivers/gpu/drm/radeon/radeon_legacy_encoders.o] Error 1
make: *** [_module_drivers/gpu/drm/radeon] Error 2

Am I missing changes from another tree?


-- 
Earthling Michel Dänzer           |                http://www.vmware.com
Libre software enthusiast         |          Debian, X and DRI developer
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
  2010-09-13  7:54     ` Michel Dänzer
@ 2010-09-15 11:38       ` Michel Dänzer
  -1 siblings, 0 replies; 26+ messages in thread
From: Michel Dänzer @ 2010-09-15 11:38 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, dri-devel

On Mon, 2010-09-13 at 09:54 +0200, Michel Dänzer wrote: 
> On Mit, 2010-09-08 at 12:32 -0400, Matthew Garrett wrote: 
> > From: Michel Dänzer <michel@daenzer.net>
> > 
> > Allows e.g. power management daemons to control the backlight level. Inspired
> > by the corresponding code in radeonfb.
> > 
> > (Updated to add backlight type and make the connector the parent device - mjg)
> > 
> > Signed-off-by: Michel Dänzer <daenzer@vmware.com>
> > Signed-off-by: Matthew Garrett <mjg@redhat.com>
> 
> Thanks for picking this up, Matthew.
> 
> Unfortunately, it fails to build here:
> 
>   CC [M]  drivers/gpu/drm/radeon/radeon_legacy_encoders.o
> drivers/gpu/drm/radeon/radeon_legacy_encoders.c: In function ‘radeon_legacy_backlight_init’:
> drivers/gpu/drm/radeon/radeon_legacy_encoders.c:358: error: implicit declaration of function ‘pmac_has_backlight_type’
> drivers/gpu/drm/radeon/radeon_legacy_encoders.c:403: error: implicit declaration of function ‘machine_is_compatible’
> make[1]: *** [drivers/gpu/drm/radeon/radeon_legacy_encoders.o] Error 1
> make: *** [_module_drivers/gpu/drm/radeon] Error 2

Also, radeon_get_connector_for_encoder() only works when a mode is set,
connector->kdev is only initialized after drm_sysfs_connector_add(), and
I deliberately chose the backlight device name ending in "bl" because
that's what pbbuttonsd looks for (though of course that could be fixed
there).

The updated patch below fixes these issues, successfully using this
right now.


>From 59ce4a62cefdef665db5ec7527860c9314a6931d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <daenzer@vmware.com>
Date: Mon, 23 Aug 2010 08:46:31 +0200
Subject: drm/radeon/kms: Expose backlight class device for legacy LVDS encoder.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Allows e.g. power management daemons to control the backlight level. Inspired
by the corresponding code in radeonfb.

(Updated to add backlight type and make the connector the parent device - mjg)

Signed-off-by: Michel Dänzer <daenzer@vmware.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
 drivers/gpu/drm/radeon/Kconfig                  |    1 +
 drivers/gpu/drm/radeon/radeon_connectors.c      |   15 ++
 drivers/gpu/drm/radeon/radeon_legacy_encoders.c |  257 ++++++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_mode.h            |   10 +
 4 files changed, 277 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 1c02d23..9746fee 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -1,6 +1,7 @@
 config DRM_RADEON_KMS
 	bool "Enable modesetting on radeon by default - NEW DRIVER"
 	depends on DRM_RADEON
+	select BACKLIGHT_CLASS_DEVICE
 	help
 	  Choose this option if you want kernel modesetting enabled by default.
 
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 31a09cd..9a9ba97 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -40,6 +40,10 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
 				       struct drm_encoder *encoder,
 				       bool connected);
 
+extern void
+radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+			     struct drm_connector *drm_connector);
+
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
@@ -1389,6 +1393,17 @@ radeon_add_legacy_connector(struct drm_device *dev,
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 	connector->display_info.subpixel_order = subpixel_order;
 	drm_sysfs_connector_add(connector);
+	if (connector_type == DRM_MODE_CONNECTOR_LVDS) {
+		struct drm_encoder *drm_encoder;
+
+		list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
+			struct radeon_encoder *radeon_encoder;
+
+			radeon_encoder = to_radeon_encoder(drm_encoder);
+			if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS)
+				radeon_legacy_backlight_init(radeon_encoder, connector);
+		}
+	}
 	return;
 
 failed:
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 0b83970..bdca317 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -28,6 +28,10 @@
 #include "radeon_drm.h"
 #include "radeon.h"
 #include "atom.h"
+#include <linux/backlight.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
 
 static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 {
@@ -39,7 +43,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 	radeon_encoder->active_device = 0;
 }
 
-static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -47,15 +51,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 	uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
 	int panel_pwr_delay = 2000;
 	bool is_mac = false;
+	uint8_t backlight_level;
 	DRM_DEBUG_KMS("\n");
 
+	lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+	backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
 	if (radeon_encoder->enc_priv) {
 		if (rdev->is_atom_bios) {
 			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
 			panel_pwr_delay = lvds->panel_pwr_delay;
+			if (lvds->bl_dev)
+				backlight_level = lvds->backlight_level;
 		} else {
 			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
 			panel_pwr_delay = lvds->panel_pwr_delay;
+			if (lvds->bl_dev)
+				backlight_level = lvds->backlight_level;
 		}
 	}
 
@@ -82,11 +94,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 		lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
 		WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
 
-		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
-		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
+		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
+				   RADEON_LVDS_BL_MOD_LEVEL_MASK);
+		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
+				  RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
+				  (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
 		if (is_mac)
 			lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
-		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
 		udelay(panel_pwr_delay * 1000);
 		WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
 		break;
@@ -95,7 +109,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 	case DRM_MODE_DPMS_OFF:
 		pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
 		WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
-		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
 		lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
 		if (is_mac) {
 			lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
@@ -119,6 +132,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 
 }
 
+static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	DRM_DEBUG("\n");
+
+	if (radeon_encoder->enc_priv) {
+		if (rdev->is_atom_bios) {
+			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+			lvds->dpms_mode = mode;
+		} else {
+			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+			lvds->dpms_mode = mode;
+		}
+	}
+
+	radeon_legacy_lvds_update(encoder, mode);
+}
+
 static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
@@ -237,9 +269,222 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
 	.disable = radeon_legacy_encoder_disable,
 };
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+#define MAX_RADEON_LEVEL 0xFF
+
+struct radeon_backlight_privdata {
+	struct radeon_encoder *encoder;
+	uint8_t negative;
+};
+
+static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	uint8_t level;
+
+	/* Convert brightness to hardware level */
+	if (bd->props.brightness < 0)
+		level = 0;
+	else if (bd->props.brightness > MAX_RADEON_LEVEL)
+		level = MAX_RADEON_LEVEL;
+	else
+		level = bd->props.brightness;
+
+	if (pdata->negative)
+		level = MAX_RADEON_LEVEL - level;
+
+	return level;
+}
+
+static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	struct radeon_encoder *radeon_encoder = pdata->encoder;
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	int dpms_mode = DRM_MODE_DPMS_ON;
+
+	if (radeon_encoder->enc_priv) {
+		if (rdev->is_atom_bios) {
+			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+			dpms_mode = lvds->dpms_mode;
+			lvds->backlight_level = radeon_legacy_lvds_level(bd);
+		} else {
+			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+			dpms_mode = lvds->dpms_mode;
+			lvds->backlight_level = radeon_legacy_lvds_level(bd);
+		}
+	}
+
+	if (bd->props.brightness > 0)
+		radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
+	else
+		radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF);
+
+	return 0;
+}
+
+static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	struct radeon_encoder *radeon_encoder = pdata->encoder;
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	uint8_t backlight_level;
+
+	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+	return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level;
+}
+
+static const struct backlight_ops radeon_backlight_ops = {
+	.get_brightness = radeon_legacy_backlight_get_brightness,
+	.update_status	= radeon_legacy_backlight_update_status,
+};
+
+void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+				  struct drm_connector *drm_connector)
+{
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct backlight_device *bd;
+	struct backlight_properties props;
+	struct radeon_backlight_privdata *pdata;
+	uint8_t backlight_level;
+
+	if (!radeon_encoder->enc_priv)
+		return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!pmac_has_backlight_type("ati") &&
+	    !pmac_has_backlight_type("mnca"))
+		return;
+#endif
+
+	pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
+	if (!pdata) {
+		DRM_ERROR("Memory allocation failed\n");
+		goto error;
+	}
+
+	props.max_brightness = MAX_RADEON_LEVEL;
+	props.type = BACKLIGHT_RAW;
+	bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
+				       pdata, &radeon_backlight_ops, &props);
+	if (IS_ERR(bd)) {
+		DRM_ERROR("Backlight registration failed\n");
+		goto error;
+	}
+
+	pdata->encoder = radeon_encoder;
+
+	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+	/* First, try to detect backlight level sense based on the assumption
+	 * that firmware set it up at full brightness
+	 */
+	if (backlight_level == 0)
+		pdata->negative = true;
+	else if (backlight_level == 0xff)
+		pdata->negative = false;
+	else {
+		/* XXX hack... maybe some day we can figure out in what direction
+		 * backlight should work on a given panel?
+		 */
+		pdata->negative = (rdev->family != CHIP_RV200 &&
+				   rdev->family != CHIP_RV250 &&
+				   rdev->family != CHIP_RV280 &&
+				   rdev->family != CHIP_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+		pdata->negative = (pdata->negative ||
+				   of_machine_is_compatible("PowerBook4,3") ||
+				   of_machine_is_compatible("PowerBook6,3") ||
+				   of_machine_is_compatible("PowerBook6,5"));
+#endif
+	}
+
+	if (rdev->is_atom_bios) {
+		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+		lvds->bl_dev = bd;
+	} else {
+		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+		lvds->bl_dev = bd;
+	}
+
+	bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
+	bd->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(bd);
+
+	DRM_INFO("radeon legacy LVDS backlight initialized\n");
+
+	return;
+
+error:
+	kfree(pdata);
+	return;
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
+{
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct backlight_device *bd = NULL;
+
+	if (!radeon_encoder->enc_priv)
+		return;
+
+	if (rdev->is_atom_bios) {
+		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+		bd = lvds->bl_dev;
+		lvds->bl_dev = NULL;
+	} else {
+		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+		bd = lvds->bl_dev;
+		lvds->bl_dev = NULL;
+	}
+
+	if (bd) {
+		struct radeon_legacy_backlight_privdata *pdata;
+
+		pdata = bl_get_data(bd);
+		backlight_device_unregister(bd);
+		kfree(pdata);
+
+		DRM_INFO("radeon legacy LVDS backlight unloaded\n");
+	}
+}
+
+#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+static void radeon_legacy_backlight_init(struct radeon_encoder *encoder)
+{
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder)
+{
+}
+
+#endif
+
+
+static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->enc_priv) {
+		radeon_legacy_backlight_exit(radeon_encoder);
+		kfree(radeon_encoder->enc_priv);
+	}
+	drm_encoder_cleanup(encoder);
+	kfree(radeon_encoder);
+}
 
 static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
-	.destroy = radeon_enc_destroy,
+	.destroy = radeon_lvds_enc_destroy,
 };
 
 static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 8f93e2b..c112624 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -302,6 +302,11 @@ struct radeon_encoder_lvds {
 	uint32_t lvds_gen_cntl;
 	/* panel mode */
 	struct drm_display_mode native_mode;
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	struct backlight_device *bl_dev;
+	int      dpms_mode;
+	uint8_t  backlight_level;
+#endif
 };
 
 struct radeon_encoder_tv_dac {
@@ -353,6 +358,11 @@ struct radeon_encoder_atom_dig {
 	struct radeon_atom_ss *ss;
 	/* panel mode */
 	struct drm_display_mode native_mode;
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	struct backlight_device *bl_dev;
+	int dpms_mode;
+	uint8_t backlight_level;
+#endif
 };
 
 struct radeon_encoder_atom_dac {
-- 
1.7.1



-- 
Earthling Michel Dänzer           |                http://www.vmware.com
Libre software enthusiast         |          Debian, X and DRI developer

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] radeon: Expose backlight class device for legacy LVDS encoder
@ 2010-09-15 11:38       ` Michel Dänzer
  0 siblings, 0 replies; 26+ messages in thread
From: Michel Dänzer @ 2010-09-15 11:38 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, dri-devel

On Mon, 2010-09-13 at 09:54 +0200, Michel Dänzer wrote: 
> On Mit, 2010-09-08 at 12:32 -0400, Matthew Garrett wrote: 
> > From: Michel Dänzer <michel@daenzer.net>
> > 
> > Allows e.g. power management daemons to control the backlight level. Inspired
> > by the corresponding code in radeonfb.
> > 
> > (Updated to add backlight type and make the connector the parent device - mjg)
> > 
> > Signed-off-by: Michel Dänzer <daenzer@vmware.com>
> > Signed-off-by: Matthew Garrett <mjg@redhat.com>
> 
> Thanks for picking this up, Matthew.
> 
> Unfortunately, it fails to build here:
> 
>   CC [M]  drivers/gpu/drm/radeon/radeon_legacy_encoders.o
> drivers/gpu/drm/radeon/radeon_legacy_encoders.c: In function ‘radeon_legacy_backlight_init’:
> drivers/gpu/drm/radeon/radeon_legacy_encoders.c:358: error: implicit declaration of function ‘pmac_has_backlight_type’
> drivers/gpu/drm/radeon/radeon_legacy_encoders.c:403: error: implicit declaration of function ‘machine_is_compatible’
> make[1]: *** [drivers/gpu/drm/radeon/radeon_legacy_encoders.o] Error 1
> make: *** [_module_drivers/gpu/drm/radeon] Error 2

Also, radeon_get_connector_for_encoder() only works when a mode is set,
connector->kdev is only initialized after drm_sysfs_connector_add(), and
I deliberately chose the backlight device name ending in "bl" because
that's what pbbuttonsd looks for (though of course that could be fixed
there).

The updated patch below fixes these issues, successfully using this
right now.


From 59ce4a62cefdef665db5ec7527860c9314a6931d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <daenzer@vmware.com>
Date: Mon, 23 Aug 2010 08:46:31 +0200
Subject: drm/radeon/kms: Expose backlight class device for legacy LVDS encoder.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Allows e.g. power management daemons to control the backlight level. Inspired
by the corresponding code in radeonfb.

(Updated to add backlight type and make the connector the parent device - mjg)

Signed-off-by: Michel Dänzer <daenzer@vmware.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
 drivers/gpu/drm/radeon/Kconfig                  |    1 +
 drivers/gpu/drm/radeon/radeon_connectors.c      |   15 ++
 drivers/gpu/drm/radeon/radeon_legacy_encoders.c |  257 ++++++++++++++++++++++-
 drivers/gpu/drm/radeon/radeon_mode.h            |   10 +
 4 files changed, 277 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 1c02d23..9746fee 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -1,6 +1,7 @@
 config DRM_RADEON_KMS
 	bool "Enable modesetting on radeon by default - NEW DRIVER"
 	depends on DRM_RADEON
+	select BACKLIGHT_CLASS_DEVICE
 	help
 	  Choose this option if you want kernel modesetting enabled by default.
 
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 31a09cd..9a9ba97 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -40,6 +40,10 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
 				       struct drm_encoder *encoder,
 				       bool connected);
 
+extern void
+radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+			     struct drm_connector *drm_connector);
+
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
@@ -1389,6 +1393,17 @@ radeon_add_legacy_connector(struct drm_device *dev,
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 	connector->display_info.subpixel_order = subpixel_order;
 	drm_sysfs_connector_add(connector);
+	if (connector_type == DRM_MODE_CONNECTOR_LVDS) {
+		struct drm_encoder *drm_encoder;
+
+		list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
+			struct radeon_encoder *radeon_encoder;
+
+			radeon_encoder = to_radeon_encoder(drm_encoder);
+			if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS)
+				radeon_legacy_backlight_init(radeon_encoder, connector);
+		}
+	}
 	return;
 
 failed:
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 0b83970..bdca317 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -28,6 +28,10 @@
 #include "radeon_drm.h"
 #include "radeon.h"
 #include "atom.h"
+#include <linux/backlight.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
 
 static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 {
@@ -39,7 +43,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 	radeon_encoder->active_device = 0;
 }
 
-static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -47,15 +51,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 	uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
 	int panel_pwr_delay = 2000;
 	bool is_mac = false;
+	uint8_t backlight_level;
 	DRM_DEBUG_KMS("\n");
 
+	lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+	backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
 	if (radeon_encoder->enc_priv) {
 		if (rdev->is_atom_bios) {
 			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
 			panel_pwr_delay = lvds->panel_pwr_delay;
+			if (lvds->bl_dev)
+				backlight_level = lvds->backlight_level;
 		} else {
 			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
 			panel_pwr_delay = lvds->panel_pwr_delay;
+			if (lvds->bl_dev)
+				backlight_level = lvds->backlight_level;
 		}
 	}
 
@@ -82,11 +94,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 		lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
 		WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
 
-		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
-		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
+		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
+				   RADEON_LVDS_BL_MOD_LEVEL_MASK);
+		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
+				  RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
+				  (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
 		if (is_mac)
 			lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
-		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
 		udelay(panel_pwr_delay * 1000);
 		WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
 		break;
@@ -95,7 +109,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 	case DRM_MODE_DPMS_OFF:
 		pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
 		WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
-		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
 		lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
 		if (is_mac) {
 			lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
@@ -119,6 +132,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 
 }
 
+static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	DRM_DEBUG("\n");
+
+	if (radeon_encoder->enc_priv) {
+		if (rdev->is_atom_bios) {
+			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+			lvds->dpms_mode = mode;
+		} else {
+			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+			lvds->dpms_mode = mode;
+		}
+	}
+
+	radeon_legacy_lvds_update(encoder, mode);
+}
+
 static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
@@ -237,9 +269,222 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
 	.disable = radeon_legacy_encoder_disable,
 };
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+#define MAX_RADEON_LEVEL 0xFF
+
+struct radeon_backlight_privdata {
+	struct radeon_encoder *encoder;
+	uint8_t negative;
+};
+
+static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	uint8_t level;
+
+	/* Convert brightness to hardware level */
+	if (bd->props.brightness < 0)
+		level = 0;
+	else if (bd->props.brightness > MAX_RADEON_LEVEL)
+		level = MAX_RADEON_LEVEL;
+	else
+		level = bd->props.brightness;
+
+	if (pdata->negative)
+		level = MAX_RADEON_LEVEL - level;
+
+	return level;
+}
+
+static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	struct radeon_encoder *radeon_encoder = pdata->encoder;
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	int dpms_mode = DRM_MODE_DPMS_ON;
+
+	if (radeon_encoder->enc_priv) {
+		if (rdev->is_atom_bios) {
+			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+			dpms_mode = lvds->dpms_mode;
+			lvds->backlight_level = radeon_legacy_lvds_level(bd);
+		} else {
+			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+			dpms_mode = lvds->dpms_mode;
+			lvds->backlight_level = radeon_legacy_lvds_level(bd);
+		}
+	}
+
+	if (bd->props.brightness > 0)
+		radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
+	else
+		radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF);
+
+	return 0;
+}
+
+static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
+{
+	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+	struct radeon_encoder *radeon_encoder = pdata->encoder;
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	uint8_t backlight_level;
+
+	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+	return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level;
+}
+
+static const struct backlight_ops radeon_backlight_ops = {
+	.get_brightness = radeon_legacy_backlight_get_brightness,
+	.update_status	= radeon_legacy_backlight_update_status,
+};
+
+void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+				  struct drm_connector *drm_connector)
+{
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct backlight_device *bd;
+	struct backlight_properties props;
+	struct radeon_backlight_privdata *pdata;
+	uint8_t backlight_level;
+
+	if (!radeon_encoder->enc_priv)
+		return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!pmac_has_backlight_type("ati") &&
+	    !pmac_has_backlight_type("mnca"))
+		return;
+#endif
+
+	pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
+	if (!pdata) {
+		DRM_ERROR("Memory allocation failed\n");
+		goto error;
+	}
+
+	props.max_brightness = MAX_RADEON_LEVEL;
+	props.type = BACKLIGHT_RAW;
+	bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
+				       pdata, &radeon_backlight_ops, &props);
+	if (IS_ERR(bd)) {
+		DRM_ERROR("Backlight registration failed\n");
+		goto error;
+	}
+
+	pdata->encoder = radeon_encoder;
+
+	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+	/* First, try to detect backlight level sense based on the assumption
+	 * that firmware set it up at full brightness
+	 */
+	if (backlight_level == 0)
+		pdata->negative = true;
+	else if (backlight_level == 0xff)
+		pdata->negative = false;
+	else {
+		/* XXX hack... maybe some day we can figure out in what direction
+		 * backlight should work on a given panel?
+		 */
+		pdata->negative = (rdev->family != CHIP_RV200 &&
+				   rdev->family != CHIP_RV250 &&
+				   rdev->family != CHIP_RV280 &&
+				   rdev->family != CHIP_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+		pdata->negative = (pdata->negative ||
+				   of_machine_is_compatible("PowerBook4,3") ||
+				   of_machine_is_compatible("PowerBook6,3") ||
+				   of_machine_is_compatible("PowerBook6,5"));
+#endif
+	}
+
+	if (rdev->is_atom_bios) {
+		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+		lvds->bl_dev = bd;
+	} else {
+		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+		lvds->bl_dev = bd;
+	}
+
+	bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
+	bd->props.power = FB_BLANK_UNBLANK;
+	backlight_update_status(bd);
+
+	DRM_INFO("radeon legacy LVDS backlight initialized\n");
+
+	return;
+
+error:
+	kfree(pdata);
+	return;
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
+{
+	struct drm_device *dev = radeon_encoder->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct backlight_device *bd = NULL;
+
+	if (!radeon_encoder->enc_priv)
+		return;
+
+	if (rdev->is_atom_bios) {
+		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+		bd = lvds->bl_dev;
+		lvds->bl_dev = NULL;
+	} else {
+		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+		bd = lvds->bl_dev;
+		lvds->bl_dev = NULL;
+	}
+
+	if (bd) {
+		struct radeon_legacy_backlight_privdata *pdata;
+
+		pdata = bl_get_data(bd);
+		backlight_device_unregister(bd);
+		kfree(pdata);
+
+		DRM_INFO("radeon legacy LVDS backlight unloaded\n");
+	}
+}
+
+#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+static void radeon_legacy_backlight_init(struct radeon_encoder *encoder)
+{
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder)
+{
+}
+
+#endif
+
+
+static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->enc_priv) {
+		radeon_legacy_backlight_exit(radeon_encoder);
+		kfree(radeon_encoder->enc_priv);
+	}
+	drm_encoder_cleanup(encoder);
+	kfree(radeon_encoder);
+}
 
 static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
-	.destroy = radeon_enc_destroy,
+	.destroy = radeon_lvds_enc_destroy,
 };
 
 static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 8f93e2b..c112624 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -302,6 +302,11 @@ struct radeon_encoder_lvds {
 	uint32_t lvds_gen_cntl;
 	/* panel mode */
 	struct drm_display_mode native_mode;
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	struct backlight_device *bl_dev;
+	int      dpms_mode;
+	uint8_t  backlight_level;
+#endif
 };
 
 struct radeon_encoder_tv_dac {
@@ -353,6 +358,11 @@ struct radeon_encoder_atom_dig {
 	struct radeon_atom_ss *ss;
 	/* panel mode */
 	struct drm_display_mode native_mode;
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+	struct backlight_device *bl_dev;
+	int dpms_mode;
+	uint8_t backlight_level;
+#endif
 };
 
 struct radeon_encoder_atom_dac {
-- 
1.7.1



-- 
Earthling Michel Dänzer           |                http://www.vmware.com
Libre software enthusiast         |          Debian, X and DRI developer

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Intel-gfx] [PATCH] Backlight: Add backlight type
  2010-09-08 16:32 ` Matthew Garrett
                   ` (3 preceding siblings ...)
  (?)
@ 2010-11-15 15:48 ` Matthew Garrett
  2010-11-15 16:44     ` Jesse Barnes
  -1 siblings, 1 reply; 26+ messages in thread
From: Matthew Garrett @ 2010-11-15 15:48 UTC (permalink / raw)
  To: linux-kernel; +Cc: intel-gfx, Richard Purdie, dri-devel

Richard, any feedback on this?

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Intel-gfx] [PATCH] Backlight: Add backlight type
  2010-11-15 15:48 ` [Intel-gfx] " Matthew Garrett
@ 2010-11-15 16:44     ` Jesse Barnes
  0 siblings, 0 replies; 26+ messages in thread
From: Jesse Barnes @ 2010-11-15 16:44 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, intel-gfx, Richard Purdie, dri-devel

On Mon, 15 Nov 2010 15:48:20 +0000
Matthew Garrett <mjg59@srcf.ucam.org> wrote:

> Richard, any feedback on this?
> 

At KS akpm said he'd likely be taking over backlight from Richard,
since Richard is very distracted with other things atm (please correct
me if I'm wrong).

So either someone needs to volunteer to maintain this subsystem (I know
how much you love backlights, maybe you'd like to do it?) or you need to
get this patch over to akpm.

-- 
Jesse Barnes, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] Backlight: Add backlight type
@ 2010-11-15 16:44     ` Jesse Barnes
  0 siblings, 0 replies; 26+ messages in thread
From: Jesse Barnes @ 2010-11-15 16:44 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: dri-devel, intel-gfx, Purdie, linux-kernel, Richard

On Mon, 15 Nov 2010 15:48:20 +0000
Matthew Garrett <mjg59@srcf.ucam.org> wrote:

> Richard, any feedback on this?
> 

At KS akpm said he'd likely be taking over backlight from Richard,
since Richard is very distracted with other things atm (please correct
me if I'm wrong).

So either someone needs to volunteer to maintain this subsystem (I know
how much you love backlights, maybe you'd like to do it?) or you need to
get this patch over to akpm.

-- 
Jesse Barnes, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Intel-gfx] [PATCH] Backlight: Add backlight type
  2010-11-15 16:44     ` Jesse Barnes
  (?)
@ 2011-03-24  6:53     ` Mike Frysinger
  2011-03-24  7:13       ` Mike Frysinger
  -1 siblings, 1 reply; 26+ messages in thread
From: Mike Frysinger @ 2011-03-24  6:53 UTC (permalink / raw)
  To: Jesse Barnes
  Cc: Matthew Garrett, linux-kernel, intel-gfx, Richard Purdie, dri-devel

On Mon, Nov 15, 2010 at 11:44, Jesse Barnes wrote:
> On Mon, 15 Nov 2010 15:48:20 +0000 Matthew Garrett wrote:
>> Richard, any feedback on this?
>>
>
> At KS akpm said he'd likely be taking over backlight from Richard,
> since Richard is very distracted with other things atm (please correct
> me if I'm wrong).
>
> So either someone needs to volunteer to maintain this subsystem (I know
> how much you love backlights, maybe you'd like to do it?) or you need to
> get this patch over to akpm.

this go anywhere ?
-mike

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Intel-gfx] [PATCH] Backlight: Add backlight type
  2011-03-24  6:53     ` [Intel-gfx] " Mike Frysinger
@ 2011-03-24  7:13       ` Mike Frysinger
  0 siblings, 0 replies; 26+ messages in thread
From: Mike Frysinger @ 2011-03-24  7:13 UTC (permalink / raw)
  To: Jesse Barnes
  Cc: Matthew Garrett, linux-kernel, intel-gfx, Richard Purdie, dri-devel

On Thu, Mar 24, 2011 at 02:53, Mike Frysinger wrote:
> On Mon, Nov 15, 2010 at 11:44, Jesse Barnes wrote:
>> On Mon, 15 Nov 2010 15:48:20 +0000 Matthew Garrett wrote:
>>> Richard, any feedback on this?
>>
>> At KS akpm said he'd likely be taking over backlight from Richard,
>> since Richard is very distracted with other things atm (please correct
>> me if I'm wrong).
>>
>> So either someone needs to volunteer to maintain this subsystem (I know
>> how much you love backlights, maybe you'd like to do it?) or you need to
>> get this patch over to akpm.
>
> this go anywhere ?

nm, i see it was just merged.  one of the things i pointed out though
is still there:
-static const char const *backlight_types[] = {
+static const char const * const backlight_types[] = {
-mike

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2011-03-24  7:14 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-08 16:32 [PATCH] Backlight: Add backlight type Matthew Garrett
2010-09-08 16:32 ` Matthew Garrett
2010-09-08 16:32 ` [PATCH] i915: Add native backlight control Matthew Garrett
2010-09-08 16:32   ` Matthew Garrett
2010-09-09 17:09   ` [Intel-gfx] " Chris Wilson
2010-09-09 17:09     ` Chris Wilson
2010-09-09 17:14     ` [Intel-gfx] " Matthew Garrett
2010-09-10 13:38   ` [PATCH] drm/i915: Expose a native backlight device Chris Wilson
2010-09-10 13:38     ` Chris Wilson
2010-09-10 13:47     ` Matthew Garrett
2010-09-10 13:47       ` Matthew Garrett
2010-09-08 16:32 ` [PATCH] radeon: Expose backlight class device for legacy LVDS encoder Matthew Garrett
2010-09-08 16:58   ` Alex Deucher
2010-09-08 17:03     ` Matthew Garrett
2010-09-08 17:03       ` Matthew Garrett
2010-09-08 17:04       ` Alex Deucher
2010-09-13  7:54   ` Michel Dänzer
2010-09-13  7:54     ` Michel Dänzer
2010-09-15 11:38     ` Michel Dänzer
2010-09-15 11:38       ` Michel Dänzer
2010-09-09 16:59 ` [PATCH] Backlight: Add backlight type Mike Frysinger
2010-11-15 15:48 ` [Intel-gfx] " Matthew Garrett
2010-11-15 16:44   ` Jesse Barnes
2010-11-15 16:44     ` Jesse Barnes
2011-03-24  6:53     ` [Intel-gfx] " Mike Frysinger
2011-03-24  7:13       ` Mike Frysinger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.