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