aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2012-08-09 13:45:01 -0400
committerMatthew Garrett <mjg@redhat.com>2012-08-17 17:34:39 -0400
commit96ff705638e3d61b1e45a047c0f9f3bb622fa32f (patch)
tree258fb8b63a724f710d445edfa7ef528ed14e5cd5 /drivers/platform
parent7e30ed6bdd91ae73c34fc37b57fcccc8640641f9 (diff)
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 <mjg@redhat.com> Cc: Bernhard Froemel <froemel@vmars.tuwien.ac.at> Cc: Seth Forshee <seth.forshee@canonical.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/apple-gmux.c179
1 files changed, 165 insertions, 14 deletions
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index c9db50729f6f..0d140e1879e7 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -18,12 +18,15 @@
18#include <linux/pnp.h> 18#include <linux/pnp.h>
19#include <linux/apple_bl.h> 19#include <linux/apple_bl.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/delay.h>
21#include <acpi/video.h> 22#include <acpi/video.h>
22#include <asm/io.h> 23#include <asm/io.h>
23 24
24struct apple_gmux_data { 25struct apple_gmux_data {
25 unsigned long iostart; 26 unsigned long iostart;
26 unsigned long iolen; 27 unsigned long iolen;
28 bool indexed;
29 struct mutex index_lock;
27 30
28 struct backlight_device *bdev; 31 struct backlight_device *bdev;
29}; 32};
@@ -45,6 +48,9 @@ struct apple_gmux_data {
45#define GMUX_PORT_DISCRETE_POWER 0x50 48#define GMUX_PORT_DISCRETE_POWER 0x50
46#define GMUX_PORT_MAX_BRIGHTNESS 0x70 49#define GMUX_PORT_MAX_BRIGHTNESS 0x70
47#define GMUX_PORT_BRIGHTNESS 0x74 50#define GMUX_PORT_BRIGHTNESS 0x74
51#define GMUX_PORT_VALUE 0xc2
52#define GMUX_PORT_READ 0xd0
53#define GMUX_PORT_WRITE 0xd4
48 54
49#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4) 55#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
50 56
@@ -59,24 +65,24 @@ struct apple_gmux_data {
59#define GMUX_BRIGHTNESS_MASK 0x00ffffff 65#define GMUX_BRIGHTNESS_MASK 0x00ffffff
60#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK 66#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
61 67
62static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port) 68static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
63{ 69{
64 return inb(gmux_data->iostart + port); 70 return inb(gmux_data->iostart + port);
65} 71}
66 72
67static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port, 73static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
68 u8 val) 74 u8 val)
69{ 75{
70 outb(val, gmux_data->iostart + port); 76 outb(val, gmux_data->iostart + port);
71} 77}
72 78
73static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port) 79static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
74{ 80{
75 return inl(gmux_data->iostart + port); 81 return inl(gmux_data->iostart + port);
76} 82}
77 83
78static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port, 84static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
79 u32 val) 85 u32 val)
80{ 86{
81 int i; 87 int i;
82 u8 tmpval; 88 u8 tmpval;
@@ -87,6 +93,144 @@ static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
87 } 93 }
88} 94}
89 95
96static 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
111static 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
128static 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
141static 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
152static 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
165static 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
184static 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
192static 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
200static 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
208static 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
217static 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
90static int gmux_get_brightness(struct backlight_device *bd) 234static int gmux_get_brightness(struct backlight_device *bd)
91{ 235{
92 struct apple_gmux_data *gmux_data = bl_get_data(bd); 236 struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -150,22 +294,29 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
150 } 294 }
151 295
152 /* 296 /*
153 * On some machines the gmux is in ACPI even thought the machine 297 * Invalid version information may indicate either that the gmux
154 * doesn't really have a gmux. Check for invalid version information 298 * device isn't present or that it's a new one that uses indexed
155 * to detect this. 299 * io
156 */ 300 */
301
157 ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR); 302 ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
158 ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR); 303 ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
159 ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); 304 ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
160 if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { 305 if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
161 pr_info("gmux device not present\n"); 306 if (gmux_is_indexed(gmux_data)) {
162 ret = -ENODEV; 307 mutex_init(&gmux_data->index_lock);
163 goto err_release; 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);
164 } 318 }
165 319
166 pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
167 ver_release);
168
169 memset(&props, 0, sizeof(props)); 320 memset(&props, 0, sizeof(props));
170 props.type = BACKLIGHT_PLATFORM; 321 props.type = BACKLIGHT_PLATFORM;
171 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); 322 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);