| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Backlight code for via-pmu | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. | 
					
						
							|  |  |  |  * Copyright (C) 2001-2002 Benjamin Herrenschmidt | 
					
						
							|  |  |  |  * Copyright (C) 2006      Michael Hanselmann <linux-kernel@hansmi.ch> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/ptrace.h>
 | 
					
						
							|  |  |  | #include <linux/adb.h>
 | 
					
						
							|  |  |  | #include <linux/pmu.h>
 | 
					
						
							|  |  |  | #include <asm/backlight.h>
 | 
					
						
							|  |  |  | #include <asm/prom.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MAX_PMU_LEVEL 0xFF
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-16 14:14:02 +01:00
										 |  |  | static const struct backlight_ops pmu_backlight_data; | 
					
						
							| 
									
										
										
										
											2006-09-29 01:58:37 -07:00
										 |  |  | static DEFINE_SPINLOCK(pmu_backlight_lock); | 
					
						
							| 
									
										
										
										
											2008-03-03 17:27:46 +11:00
										 |  |  | static int sleeping, uses_pmu_bl; | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | static u8 bl_curve[FB_BACKLIGHT_LEVELS]; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | static void pmu_backlight_init_curve(u8 off, u8 min, u8 max) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-20 15:00:21 +11:00
										 |  |  | 	int i, flat, count, range = (max - min); | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	bl_curve[0] = off; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat) | 
					
						
							|  |  |  | 		bl_curve[flat] = min; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	count = FB_BACKLIGHT_LEVELS * 15 / 16; | 
					
						
							|  |  |  | 	for (i = 0; i < count; ++i) | 
					
						
							|  |  |  | 		bl_curve[flat + i] = min + (range * (i + 1) / count); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int pmu_backlight_curve_lookup(int value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int level = (FB_BACKLIGHT_LEVELS - 1); | 
					
						
							|  |  |  | 	int i, max = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Look for biggest value */ | 
					
						
							|  |  |  | 	for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) | 
					
						
							|  |  |  | 		max = max((int)bl_curve[i], max); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Look for nearest value */ | 
					
						
							|  |  |  | 	for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) { | 
					
						
							|  |  |  | 		int diff = abs(bl_curve[i] - value); | 
					
						
							|  |  |  | 		if (diff < max) { | 
					
						
							|  |  |  | 			max = diff; | 
					
						
							|  |  |  | 			level = i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return level; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int pmu_backlight_get_level_brightness(int level) | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int pmulevel; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Get and convert the value */ | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 	pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	if (pmulevel < 0) | 
					
						
							|  |  |  | 		pmulevel = 0; | 
					
						
							|  |  |  | 	else if (pmulevel > MAX_PMU_LEVEL) | 
					
						
							|  |  |  | 		pmulevel = MAX_PMU_LEVEL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pmulevel; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-20 15:00:21 +11:00
										 |  |  | static int __pmu_backlight_update_status(struct backlight_device *bd) | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct adb_request req; | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 	int level = bd->props.brightness; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 	if (bd->props.power != FB_BLANK_UNBLANK || | 
					
						
							|  |  |  | 	    bd->props.fb_blank != FB_BLANK_UNBLANK) | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 		level = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 	if (level > 0) { | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 		int pmulevel = pmu_backlight_get_level_brightness(level); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); | 
					
						
							|  |  |  | 		pmu_wait_complete(&req); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 		pmu_request(&req, NULL, 2, PMU_POWER_CTRL, | 
					
						
							|  |  |  | 			PMU_POW_BACKLIGHT | PMU_POW_ON); | 
					
						
							|  |  |  | 		pmu_wait_complete(&req); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		pmu_request(&req, NULL, 2, PMU_POWER_CTRL, | 
					
						
							|  |  |  | 			PMU_POW_BACKLIGHT | PMU_POW_OFF); | 
					
						
							|  |  |  | 		pmu_wait_complete(&req); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-20 15:00:21 +11:00
										 |  |  | static int pmu_backlight_update_status(struct backlight_device *bd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	int rc = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&pmu_backlight_lock, flags); | 
					
						
							|  |  |  | 	/* Don't update brightness when sleeping */ | 
					
						
							|  |  |  | 	if (!sleeping) | 
					
						
							|  |  |  | 		rc = __pmu_backlight_update_status(bd); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&pmu_backlight_lock, flags); | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-16 14:14:02 +01:00
										 |  |  | static const struct backlight_ops pmu_backlight_data = { | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	.update_status	= pmu_backlight_update_status, | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | #ifdef CONFIG_PM
 | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | void pmu_backlight_set_sleep(int sleep) | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&pmu_backlight_lock, flags); | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 	sleeping = sleep; | 
					
						
							| 
									
										
										
										
											2008-03-03 17:27:46 +11:00
										 |  |  | 	if (pmac_backlight && uses_pmu_bl) { | 
					
						
							| 
									
										
										
										
											2007-12-20 15:00:21 +11:00
										 |  |  | 		if (sleep) { | 
					
						
							|  |  |  | 			struct adb_request req; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			pmu_request(&req, NULL, 2, PMU_POWER_CTRL, | 
					
						
							|  |  |  | 				    PMU_POW_BACKLIGHT | PMU_POW_OFF); | 
					
						
							|  |  |  | 			pmu_wait_complete(&req); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			__pmu_backlight_update_status(pmac_backlight); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 	spin_unlock_irqrestore(&pmu_backlight_lock, flags); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | #endif /* CONFIG_PM */
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | void __init pmu_backlight_init() | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-02-17 16:39:44 -05:00
										 |  |  | 	struct backlight_properties props; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	struct backlight_device *bd; | 
					
						
							|  |  |  | 	char name[10]; | 
					
						
							|  |  |  | 	int level, autosave; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Special case for the old PowerBook since I can't test on it */ | 
					
						
							|  |  |  | 	autosave = | 
					
						
							| 
									
										
										
										
											2010-02-01 21:34:14 -07:00
										 |  |  | 		of_machine_is_compatible("AAPL,3400/2400") || | 
					
						
							|  |  |  | 		of_machine_is_compatible("AAPL,3500"); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!autosave && | 
					
						
							|  |  |  | 	    !pmac_has_backlight_type("pmu") && | 
					
						
							| 
									
										
										
										
											2010-02-01 21:34:14 -07:00
										 |  |  | 	    !of_machine_is_compatible("AAPL,PowerBook1998") && | 
					
						
							|  |  |  | 	    !of_machine_is_compatible("PowerBook1,1")) | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 	snprintf(name, sizeof(name), "pmubl"); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-17 16:39:44 -05:00
										 |  |  | 	memset(&props, 0, sizeof(struct backlight_properties)); | 
					
						
							| 
									
										
										
										
											2011-03-22 16:30:21 -07:00
										 |  |  | 	props.type = BACKLIGHT_PLATFORM; | 
					
						
							| 
									
										
										
										
											2010-02-17 16:39:44 -05:00
										 |  |  | 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1; | 
					
						
							|  |  |  | 	bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data, | 
					
						
							|  |  |  | 				       &props); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	if (IS_ERR(bd)) { | 
					
						
							| 
									
										
										
										
											2007-12-20 15:00:21 +11:00
										 |  |  | 		printk(KERN_ERR "PMU Backlight registration failed\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-03-03 17:27:46 +11:00
										 |  |  | 	uses_pmu_bl = 1; | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 	pmu_backlight_init_curve(0x7F, 0x46, 0x0E); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 	level = bd->props.max_brightness; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (autosave) { | 
					
						
							|  |  |  | 		/* read autosaved value if available */ | 
					
						
							|  |  |  | 		struct adb_request req; | 
					
						
							|  |  |  | 		pmu_request(&req, NULL, 2, 0xd9, 0); | 
					
						
							|  |  |  | 		pmu_wait_complete(&req); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-31 21:27:49 -07:00
										 |  |  | 		level = pmu_backlight_curve_lookup( | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 				(req.reply[0] >> 4) * | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 				bd->props.max_brightness / 15); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 	bd->props.brightness = level; | 
					
						
							|  |  |  | 	bd->props.power = FB_BLANK_UNBLANK; | 
					
						
							| 
									
										
										
										
											2007-02-08 22:25:09 +00:00
										 |  |  | 	backlight_update_status(bd); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-20 15:00:21 +11:00
										 |  |  | 	printk(KERN_INFO "PMU Backlight initialized (%s)\n", name); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | } |