| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Miscellaneous procedures for dealing with the PowerMac hardware. | 
					
						
							|  |  |  |  * Contains support for the backlight. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   Copyright (C) 2000 Benjamin Herrenschmidt | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  |  *   Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | #include <linux/fb.h>
 | 
					
						
							|  |  |  | #include <linux/backlight.h>
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | #include <linux/adb.h>
 | 
					
						
							|  |  |  | #include <linux/pmu.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-26 16:09:06 -07:00
										 |  |  | #include <linux/atomic.h>
 | 
					
						
							| 
									
										
										
										
											2011-05-27 10:46:24 -04:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | #include <asm/prom.h>
 | 
					
						
							|  |  |  | #include <asm/backlight.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | #define OLD_BACKLIGHT_MAX 15
 | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-05 19:36:26 +00:00
										 |  |  | static void pmac_backlight_key_worker(struct work_struct *work); | 
					
						
							|  |  |  | static void pmac_backlight_set_legacy_worker(struct work_struct *work); | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-05 19:36:26 +00:00
										 |  |  | static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker); | 
					
						
							|  |  |  | static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker); | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | /* Although these variables are used in interrupt context, it makes no sense to
 | 
					
						
							|  |  |  |  * protect them. No user is able to produce enough key events per second and | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  |  * notice the errors that might happen. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int pmac_backlight_key_queued; | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | static int pmac_backlight_set_legacy_queued; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* The via-pmu code allows the backlight to be grabbed, in which case the
 | 
					
						
							|  |  |  |  * in-kernel control of the brightness needs to be disabled. This should | 
					
						
							|  |  |  |  * only be used by really old PowerBooks. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0); | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-08 22:25:09 +00:00
										 |  |  | /* Protect the pmac_backlight variable below.
 | 
					
						
							|  |  |  |    You should hold this lock when using the pmac_backlight pointer to | 
					
						
							|  |  |  |    prevent its potential removal. */ | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | DEFINE_MUTEX(pmac_backlight_mutex); | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | /* Main backlight storage
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  |  * Backlight drivers in this variable are required to have the "ops" | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  |  * attribute set and to have an update_status function. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * We can only store one backlight here, but since Apple laptops have only one | 
					
						
							|  |  |  |  * internal display, it doesn't matter. Other backlight drivers can be used | 
					
						
							|  |  |  |  * independently. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct backlight_device *pmac_backlight; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | int pmac_has_backlight_type(const char *type) | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-04-24 13:53:04 +10:00
										 |  |  | 	struct device_node* bk_node = of_find_node_by_name(NULL, "backlight"); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 	if (bk_node) { | 
					
						
							| 
									
										
										
										
											2007-04-03 22:26:41 +10:00
										 |  |  | 		const char *prop = of_get_property(bk_node, | 
					
						
							| 
									
										
										
										
											2006-07-12 15:40:29 +10:00
										 |  |  | 				"backlight-control", NULL); | 
					
						
							| 
									
										
										
										
											2007-04-24 13:53:04 +10:00
										 |  |  | 		if (prop && strncmp(prop, type, strlen(type)) == 0) { | 
					
						
							|  |  |  | 			of_node_put(bk_node); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 			return 1; | 
					
						
							| 
									
										
										
										
											2007-04-24 13:53:04 +10:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		of_node_put(bk_node); | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | int pmac_backlight_curve_lookup(struct fb_info *info, int value) | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	int level = (FB_BACKLIGHT_LEVELS - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (info && info->bl_dev) { | 
					
						
							|  |  |  | 		int i, max = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Look for biggest value */ | 
					
						
							|  |  |  | 		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) | 
					
						
							|  |  |  | 			max = max((int)info->bl_curve[i], max); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Look for nearest value */ | 
					
						
							|  |  |  | 		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) { | 
					
						
							|  |  |  | 			int diff = abs(info->bl_curve[i] - value); | 
					
						
							|  |  |  | 			if (diff < max) { | 
					
						
							|  |  |  | 				max = diff; | 
					
						
							|  |  |  | 				level = i; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return level; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-05 19:36:26 +00:00
										 |  |  | static void pmac_backlight_key_worker(struct work_struct *work) | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 	if (atomic_read(&kernel_backlight_disabled)) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	mutex_lock(&pmac_backlight_mutex); | 
					
						
							|  |  |  | 	if (pmac_backlight) { | 
					
						
							|  |  |  | 		struct backlight_properties *props; | 
					
						
							|  |  |  | 		int brightness; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 		props = &pmac_backlight->props; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		brightness = props->brightness + | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | 			((pmac_backlight_key_queued?-1:1) * | 
					
						
							|  |  |  | 			 (props->max_brightness / 15)); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (brightness < 0) | 
					
						
							|  |  |  | 			brightness = 0; | 
					
						
							|  |  |  | 		else if (brightness > props->max_brightness) | 
					
						
							|  |  |  | 			brightness = props->max_brightness; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		props->brightness = brightness; | 
					
						
							| 
									
										
										
										
											2007-02-08 22:25:09 +00:00
										 |  |  | 		backlight_update_status(pmac_backlight); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	mutex_unlock(&pmac_backlight_mutex); | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | /* This function is called in interrupt context */ | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | void pmac_backlight_key(int direction) | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | 	if (atomic_read(&kernel_backlight_disabled)) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | 	/* we can receive multiple interrupts here, but the scheduled work
 | 
					
						
							|  |  |  | 	 * will run only once, with the last value | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	pmac_backlight_key_queued = direction; | 
					
						
							|  |  |  | 	schedule_work(&pmac_backlight_key_work); | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | static int __pmac_backlight_set_legacy_brightness(int brightness) | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	int error = -ENXIO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_lock(&pmac_backlight_mutex); | 
					
						
							|  |  |  | 	if (pmac_backlight) { | 
					
						
							|  |  |  | 		struct backlight_properties *props; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 		props = &pmac_backlight->props; | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 		props->brightness = brightness * | 
					
						
							| 
									
										
										
										
											2006-06-28 04:26:55 -07:00
										 |  |  | 			(props->max_brightness + 1) / | 
					
						
							|  |  |  | 			(OLD_BACKLIGHT_MAX + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (props->brightness > props->max_brightness) | 
					
						
							|  |  |  | 			props->brightness = props->max_brightness; | 
					
						
							|  |  |  | 		else if (props->brightness < 0) | 
					
						
							|  |  |  | 			props->brightness = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-08 22:25:09 +00:00
										 |  |  | 		backlight_update_status(pmac_backlight); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		error = 0; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	mutex_unlock(&pmac_backlight_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return error; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-05 19:36:26 +00:00
										 |  |  | static void pmac_backlight_set_legacy_worker(struct work_struct *work) | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (atomic_read(&kernel_backlight_disabled)) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This function is called in interrupt context */ | 
					
						
							|  |  |  | void pmac_backlight_set_legacy_brightness_pmu(int brightness) { | 
					
						
							|  |  |  | 	if (atomic_read(&kernel_backlight_disabled)) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pmac_backlight_set_legacy_queued = brightness; | 
					
						
							|  |  |  | 	schedule_work(&pmac_backlight_set_legacy_work); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int pmac_backlight_set_legacy_brightness(int brightness) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return __pmac_backlight_set_legacy_brightness(brightness); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | int pmac_backlight_get_legacy_brightness() | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	int result = -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	mutex_lock(&pmac_backlight_mutex); | 
					
						
							|  |  |  | 	if (pmac_backlight) { | 
					
						
							|  |  |  | 		struct backlight_properties *props; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 23:07:48 +00:00
										 |  |  | 		props = &pmac_backlight->props; | 
					
						
							| 
									
										
										
										
											2006-06-28 04:26:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 		result = props->brightness * | 
					
						
							| 
									
										
										
										
											2006-06-28 04:26:55 -07:00
										 |  |  | 			(OLD_BACKLIGHT_MAX + 1) / | 
					
						
							|  |  |  | 			(props->max_brightness + 1); | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	mutex_unlock(&pmac_backlight_mutex); | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 05:47:08 -07:00
										 |  |  | 	return result; | 
					
						
							| 
									
										
										
										
											2005-09-26 16:04:21 +10:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-30 03:04:19 -07:00
										 |  |  | void pmac_backlight_disable() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	atomic_inc(&kernel_backlight_disabled); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void pmac_backlight_enable() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	atomic_dec(&kernel_backlight_disabled); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-10 04:44:45 -07:00
										 |  |  | EXPORT_SYMBOL_GPL(pmac_backlight); | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(pmac_backlight_mutex); | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(pmac_has_backlight_type); |