Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/powermac/backlight.c
26481 views
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 <[email protected]>
8
*
9
*/
10
11
#include <linux/kernel.h>
12
#include <linux/backlight.h>
13
#include <linux/adb.h>
14
#include <linux/pmu.h>
15
#include <linux/atomic.h>
16
#include <linux/export.h>
17
#include <asm/backlight.h>
18
19
#define OLD_BACKLIGHT_MAX 15
20
21
static void pmac_backlight_key_worker(struct work_struct *work);
22
static void pmac_backlight_set_legacy_worker(struct work_struct *work);
23
24
static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);
25
static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);
26
27
/* Although these variables are used in interrupt context, it makes no sense to
28
* protect them. No user is able to produce enough key events per second and
29
* notice the errors that might happen.
30
*/
31
static int pmac_backlight_key_queued;
32
static int pmac_backlight_set_legacy_queued;
33
34
/* The via-pmu code allows the backlight to be grabbed, in which case the
35
* in-kernel control of the brightness needs to be disabled. This should
36
* only be used by really old PowerBooks.
37
*/
38
static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
39
40
/* Protect the pmac_backlight variable below.
41
You should hold this lock when using the pmac_backlight pointer to
42
prevent its potential removal. */
43
DEFINE_MUTEX(pmac_backlight_mutex);
44
45
/* Main backlight storage
46
*
47
* Backlight drivers in this variable are required to have the "ops"
48
* attribute set and to have an update_status function.
49
*
50
* We can only store one backlight here, but since Apple laptops have only one
51
* internal display, it doesn't matter. Other backlight drivers can be used
52
* independently.
53
*
54
*/
55
struct backlight_device *pmac_backlight;
56
57
int pmac_has_backlight_type(const char *type)
58
{
59
struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
60
int i = of_property_match_string(bk_node, "backlight-control", type);
61
62
of_node_put(bk_node);
63
return i >= 0;
64
}
65
66
static void pmac_backlight_key_worker(struct work_struct *work)
67
{
68
if (atomic_read(&kernel_backlight_disabled))
69
return;
70
71
mutex_lock(&pmac_backlight_mutex);
72
if (pmac_backlight) {
73
struct backlight_properties *props;
74
int brightness;
75
76
props = &pmac_backlight->props;
77
78
brightness = props->brightness +
79
((pmac_backlight_key_queued?-1:1) *
80
(props->max_brightness / 15));
81
82
if (brightness < 0)
83
brightness = 0;
84
else if (brightness > props->max_brightness)
85
brightness = props->max_brightness;
86
87
props->brightness = brightness;
88
backlight_update_status(pmac_backlight);
89
}
90
mutex_unlock(&pmac_backlight_mutex);
91
}
92
93
/* This function is called in interrupt context */
94
void pmac_backlight_key(int direction)
95
{
96
if (atomic_read(&kernel_backlight_disabled))
97
return;
98
99
/* we can receive multiple interrupts here, but the scheduled work
100
* will run only once, with the last value
101
*/
102
pmac_backlight_key_queued = direction;
103
schedule_work(&pmac_backlight_key_work);
104
}
105
106
static int __pmac_backlight_set_legacy_brightness(int brightness)
107
{
108
int error = -ENXIO;
109
110
mutex_lock(&pmac_backlight_mutex);
111
if (pmac_backlight) {
112
struct backlight_properties *props;
113
114
props = &pmac_backlight->props;
115
props->brightness = brightness *
116
(props->max_brightness + 1) /
117
(OLD_BACKLIGHT_MAX + 1);
118
119
if (props->brightness > props->max_brightness)
120
props->brightness = props->max_brightness;
121
else if (props->brightness < 0)
122
props->brightness = 0;
123
124
backlight_update_status(pmac_backlight);
125
126
error = 0;
127
}
128
mutex_unlock(&pmac_backlight_mutex);
129
130
return error;
131
}
132
133
static void pmac_backlight_set_legacy_worker(struct work_struct *work)
134
{
135
if (atomic_read(&kernel_backlight_disabled))
136
return;
137
138
__pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
139
}
140
141
/* This function is called in interrupt context */
142
void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
143
if (atomic_read(&kernel_backlight_disabled))
144
return;
145
146
pmac_backlight_set_legacy_queued = brightness;
147
schedule_work(&pmac_backlight_set_legacy_work);
148
}
149
150
int pmac_backlight_set_legacy_brightness(int brightness)
151
{
152
return __pmac_backlight_set_legacy_brightness(brightness);
153
}
154
155
int pmac_backlight_get_legacy_brightness(void)
156
{
157
int result = -ENXIO;
158
159
mutex_lock(&pmac_backlight_mutex);
160
if (pmac_backlight) {
161
struct backlight_properties *props;
162
163
props = &pmac_backlight->props;
164
165
result = props->brightness *
166
(OLD_BACKLIGHT_MAX + 1) /
167
(props->max_brightness + 1);
168
}
169
mutex_unlock(&pmac_backlight_mutex);
170
171
return result;
172
}
173
174
void pmac_backlight_disable(void)
175
{
176
atomic_inc(&kernel_backlight_disabled);
177
}
178
179
void pmac_backlight_enable(void)
180
{
181
atomic_dec(&kernel_backlight_disabled);
182
}
183
184
EXPORT_SYMBOL_GPL(pmac_backlight);
185
EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
186
EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
187
188