Skip to content

Commit 96ff705

Browse files
author
Matthew Garrett
committed
apple_gmux: Add support for newer hardware
New gmux devices have a different method for accessing the registers. Update the driver to cope. Incorporates feedback from Bernhard Froemel. Signed-off-by: Matthew Garrett <[email protected]> Cc: Bernhard Froemel <[email protected]> Cc: Seth Forshee <[email protected]>
1 parent 7e30ed6 commit 96ff705

File tree

1 file changed

+165
-14
lines changed

1 file changed

+165
-14
lines changed

drivers/platform/x86/apple-gmux.c

Lines changed: 165 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
#include <linux/pnp.h>
1919
#include <linux/apple_bl.h>
2020
#include <linux/slab.h>
21+
#include <linux/delay.h>
2122
#include <acpi/video.h>
2223
#include <asm/io.h>
2324

2425
struct apple_gmux_data {
2526
unsigned long iostart;
2627
unsigned long iolen;
28+
bool indexed;
29+
struct mutex index_lock;
2730

2831
struct backlight_device *bdev;
2932
};
@@ -45,6 +48,9 @@ struct apple_gmux_data {
4548
#define GMUX_PORT_DISCRETE_POWER 0x50
4649
#define GMUX_PORT_MAX_BRIGHTNESS 0x70
4750
#define GMUX_PORT_BRIGHTNESS 0x74
51+
#define GMUX_PORT_VALUE 0xc2
52+
#define GMUX_PORT_READ 0xd0
53+
#define GMUX_PORT_WRITE 0xd4
4854

4955
#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
5056

@@ -59,24 +65,24 @@ struct apple_gmux_data {
5965
#define GMUX_BRIGHTNESS_MASK 0x00ffffff
6066
#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
6167

62-
static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
68+
static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
6369
{
6470
return inb(gmux_data->iostart + port);
6571
}
6672

67-
static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
73+
static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
6874
u8 val)
6975
{
7076
outb(val, gmux_data->iostart + port);
7177
}
7278

73-
static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
79+
static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
7480
{
7581
return inl(gmux_data->iostart + port);
7682
}
7783

78-
static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
79-
u32 val)
84+
static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
85+
u32 val)
8086
{
8187
int i;
8288
u8 tmpval;
@@ -87,6 +93,144 @@ static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
8793
}
8894
}
8995

96+
static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
97+
{
98+
int i = 200;
99+
u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
100+
101+
while (i && (gwr & 0x01)) {
102+
inb(gmux_data->iostart + GMUX_PORT_READ);
103+
gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
104+
udelay(100);
105+
i--;
106+
}
107+
108+
return !!i;
109+
}
110+
111+
static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
112+
{
113+
int i = 200;
114+
u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
115+
116+
while (i && !(gwr & 0x01)) {
117+
gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
118+
udelay(100);
119+
i--;
120+
}
121+
122+
if (gwr & 0x01)
123+
inb(gmux_data->iostart + GMUX_PORT_READ);
124+
125+
return !!i;
126+
}
127+
128+
static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
129+
{
130+
u8 val;
131+
132+
mutex_lock(&gmux_data->index_lock);
133+
outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
134+
gmux_index_wait_ready(gmux_data);
135+
val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
136+
mutex_unlock(&gmux_data->index_lock);
137+
138+
return val;
139+
}
140+
141+
static void gmux_index_write8(struct apple_gmux_data *gmux_data, int port,
142+
u8 val)
143+
{
144+
mutex_lock(&gmux_data->index_lock);
145+
outb(val, gmux_data->iostart + GMUX_PORT_VALUE);
146+
gmux_index_wait_ready(gmux_data);
147+
outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
148+
gmux_index_wait_complete(gmux_data);
149+
mutex_unlock(&gmux_data->index_lock);
150+
}
151+
152+
static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
153+
{
154+
u32 val;
155+
156+
mutex_lock(&gmux_data->index_lock);
157+
outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
158+
gmux_index_wait_ready(gmux_data);
159+
val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
160+
mutex_unlock(&gmux_data->index_lock);
161+
162+
return val;
163+
}
164+
165+
static void gmux_index_write32(struct apple_gmux_data *gmux_data, int port,
166+
u32 val)
167+
{
168+
int i;
169+
u8 tmpval;
170+
171+
mutex_lock(&gmux_data->index_lock);
172+
173+
for (i = 0; i < 4; i++) {
174+
tmpval = (val >> (i * 8)) & 0xff;
175+
outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i);
176+
}
177+
178+
gmux_index_wait_ready(gmux_data);
179+
outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
180+
gmux_index_wait_complete(gmux_data);
181+
mutex_unlock(&gmux_data->index_lock);
182+
}
183+
184+
static u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
185+
{
186+
if (gmux_data->indexed)
187+
return gmux_index_read8(gmux_data, port);
188+
else
189+
return gmux_pio_read8(gmux_data, port);
190+
}
191+
192+
static void gmux_write8(struct apple_gmux_data *gmux_data, int port, u8 val)
193+
{
194+
if (gmux_data->indexed)
195+
gmux_index_write8(gmux_data, port, val);
196+
else
197+
gmux_pio_write8(gmux_data, port, val);
198+
}
199+
200+
static u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
201+
{
202+
if (gmux_data->indexed)
203+
return gmux_index_read32(gmux_data, port);
204+
else
205+
return gmux_pio_read32(gmux_data, port);
206+
}
207+
208+
static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
209+
u32 val)
210+
{
211+
if (gmux_data->indexed)
212+
gmux_index_write32(gmux_data, port, val);
213+
else
214+
gmux_pio_write32(gmux_data, port, val);
215+
}
216+
217+
static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
218+
{
219+
u16 val;
220+
221+
outb(0xaa, gmux_data->iostart + 0xcc);
222+
outb(0x55, gmux_data->iostart + 0xcd);
223+
outb(0x00, gmux_data->iostart + 0xce);
224+
225+
val = inb(gmux_data->iostart + 0xcc) |
226+
(inb(gmux_data->iostart + 0xcd) << 8);
227+
228+
if (val == 0x55aa)
229+
return true;
230+
231+
return false;
232+
}
233+
90234
static int gmux_get_brightness(struct backlight_device *bd)
91235
{
92236
struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -150,22 +294,29 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
150294
}
151295

152296
/*
153-
* On some machines the gmux is in ACPI even thought the machine
154-
* doesn't really have a gmux. Check for invalid version information
155-
* to detect this.
297+
* Invalid version information may indicate either that the gmux
298+
* device isn't present or that it's a new one that uses indexed
299+
* io
156300
*/
301+
157302
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
158303
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
159304
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
160305
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
161-
pr_info("gmux device not present\n");
162-
ret = -ENODEV;
163-
goto err_release;
306+
if (gmux_is_indexed(gmux_data)) {
307+
mutex_init(&gmux_data->index_lock);
308+
gmux_data->indexed = true;
309+
} else {
310+
pr_info("gmux device not present\n");
311+
ret = -ENODEV;
312+
goto err_release;
313+
}
314+
pr_info("Found indexed gmux\n");
315+
} else {
316+
pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
317+
ver_release);
164318
}
165319

166-
pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
167-
ver_release);
168-
169320
memset(&props, 0, sizeof(props));
170321
props.type = BACKLIGHT_PLATFORM;
171322
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);

0 commit comments

Comments
 (0)