PageRenderTime 41ms CodeModel.GetById 28ms app.highlight 10ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/powerpc/platforms/powermac/backlight.c

http://github.com/mirrors/linux
C | 221 lines | 139 code | 45 blank | 37 comment | 22 complexity | 8df7b62a66ef4d2acaa368b526179c15 MD5 | raw file
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Miscellaneous procedures for dealing with the PowerMac hardware.
  4 * Contains support for the backlight.
  5 *
  6 *   Copyright (C) 2000 Benjamin Herrenschmidt
  7 *   Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  8 *
  9 */
 10
 11#include <linux/kernel.h>
 12#include <linux/fb.h>
 13#include <linux/backlight.h>
 14#include <linux/adb.h>
 15#include <linux/pmu.h>
 16#include <linux/atomic.h>
 17#include <linux/export.h>
 18#include <asm/prom.h>
 19#include <asm/backlight.h>
 20
 21#define OLD_BACKLIGHT_MAX 15
 22
 23static void pmac_backlight_key_worker(struct work_struct *work);
 24static void pmac_backlight_set_legacy_worker(struct work_struct *work);
 25
 26static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);
 27static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);
 28
 29/* Although these variables are used in interrupt context, it makes no sense to
 30 * protect them. No user is able to produce enough key events per second and
 31 * notice the errors that might happen.
 32 */
 33static int pmac_backlight_key_queued;
 34static int pmac_backlight_set_legacy_queued;
 35
 36/* The via-pmu code allows the backlight to be grabbed, in which case the
 37 * in-kernel control of the brightness needs to be disabled. This should
 38 * only be used by really old PowerBooks.
 39 */
 40static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
 41
 42/* Protect the pmac_backlight variable below.
 43   You should hold this lock when using the pmac_backlight pointer to
 44   prevent its potential removal. */
 45DEFINE_MUTEX(pmac_backlight_mutex);
 46
 47/* Main backlight storage
 48 *
 49 * Backlight drivers in this variable are required to have the "ops"
 50 * attribute set and to have an update_status function.
 51 *
 52 * We can only store one backlight here, but since Apple laptops have only one
 53 * internal display, it doesn't matter. Other backlight drivers can be used
 54 * independently.
 55 *
 56 */
 57struct backlight_device *pmac_backlight;
 58
 59int pmac_has_backlight_type(const char *type)
 60{
 61	struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
 62
 63	if (bk_node) {
 64		const char *prop = of_get_property(bk_node,
 65				"backlight-control", NULL);
 66		if (prop && strncmp(prop, type, strlen(type)) == 0) {
 67			of_node_put(bk_node);
 68			return 1;
 69		}
 70		of_node_put(bk_node);
 71	}
 72
 73	return 0;
 74}
 75
 76int pmac_backlight_curve_lookup(struct fb_info *info, int value)
 77{
 78	int level = (FB_BACKLIGHT_LEVELS - 1);
 79
 80	if (info && info->bl_dev) {
 81		int i, max = 0;
 82
 83		/* Look for biggest value */
 84		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
 85			max = max((int)info->bl_curve[i], max);
 86
 87		/* Look for nearest value */
 88		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
 89			int diff = abs(info->bl_curve[i] - value);
 90			if (diff < max) {
 91				max = diff;
 92				level = i;
 93			}
 94		}
 95
 96	}
 97
 98	return level;
 99}
100
101static void pmac_backlight_key_worker(struct work_struct *work)
102{
103	if (atomic_read(&kernel_backlight_disabled))
104		return;
105
106	mutex_lock(&pmac_backlight_mutex);
107	if (pmac_backlight) {
108		struct backlight_properties *props;
109		int brightness;
110
111		props = &pmac_backlight->props;
112
113		brightness = props->brightness +
114			((pmac_backlight_key_queued?-1:1) *
115			 (props->max_brightness / 15));
116
117		if (brightness < 0)
118			brightness = 0;
119		else if (brightness > props->max_brightness)
120			brightness = props->max_brightness;
121
122		props->brightness = brightness;
123		backlight_update_status(pmac_backlight);
124	}
125	mutex_unlock(&pmac_backlight_mutex);
126}
127
128/* This function is called in interrupt context */
129void pmac_backlight_key(int direction)
130{
131	if (atomic_read(&kernel_backlight_disabled))
132		return;
133
134	/* we can receive multiple interrupts here, but the scheduled work
135	 * will run only once, with the last value
136	 */
137	pmac_backlight_key_queued = direction;
138	schedule_work(&pmac_backlight_key_work);
139}
140
141static int __pmac_backlight_set_legacy_brightness(int brightness)
142{
143	int error = -ENXIO;
144
145	mutex_lock(&pmac_backlight_mutex);
146	if (pmac_backlight) {
147		struct backlight_properties *props;
148
149		props = &pmac_backlight->props;
150		props->brightness = brightness *
151			(props->max_brightness + 1) /
152			(OLD_BACKLIGHT_MAX + 1);
153
154		if (props->brightness > props->max_brightness)
155			props->brightness = props->max_brightness;
156		else if (props->brightness < 0)
157			props->brightness = 0;
158
159		backlight_update_status(pmac_backlight);
160
161		error = 0;
162	}
163	mutex_unlock(&pmac_backlight_mutex);
164
165	return error;
166}
167
168static void pmac_backlight_set_legacy_worker(struct work_struct *work)
169{
170	if (atomic_read(&kernel_backlight_disabled))
171		return;
172
173	__pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
174}
175
176/* This function is called in interrupt context */
177void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
178	if (atomic_read(&kernel_backlight_disabled))
179		return;
180
181	pmac_backlight_set_legacy_queued = brightness;
182	schedule_work(&pmac_backlight_set_legacy_work);
183}
184
185int pmac_backlight_set_legacy_brightness(int brightness)
186{
187	return __pmac_backlight_set_legacy_brightness(brightness);
188}
189
190int pmac_backlight_get_legacy_brightness(void)
191{
192	int result = -ENXIO;
193
194	mutex_lock(&pmac_backlight_mutex);
195	if (pmac_backlight) {
196		struct backlight_properties *props;
197
198		props = &pmac_backlight->props;
199
200		result = props->brightness *
201			(OLD_BACKLIGHT_MAX + 1) /
202			(props->max_brightness + 1);
203	}
204	mutex_unlock(&pmac_backlight_mutex);
205
206	return result;
207}
208
209void pmac_backlight_disable(void)
210{
211	atomic_inc(&kernel_backlight_disabled);
212}
213
214void pmac_backlight_enable(void)
215{
216	atomic_dec(&kernel_backlight_disabled);
217}
218
219EXPORT_SYMBOL_GPL(pmac_backlight);
220EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
221EXPORT_SYMBOL_GPL(pmac_has_backlight_type);