OSDN Git Service

Initial lollipop-x86 porting
[android-x86/device-generic-common.git] / tp_smapi / thinkpad_ec.c
1 /*
2  *  thinkpad_ec.c - ThinkPad embedded controller LPC3 functions
3  *
4  *  The embedded controller on ThinkPad laptops has a non-standard interface,
5  *  where LPC channel 3 of the H8S EC chip is hooked up to IO ports
6  *  0x1600-0x161F and implements (a special case of) the H8S LPC protocol.
7  *  The EC LPC interface provides various system management services (currently
8  *  known: battery information and accelerometer readouts). This driver
9  *  provides access and mutual exclusion for the EC interface.
10 *
11  *  The LPC protocol and terminology are documented here:
12  *  "H8S/2104B Group Hardware Manual",
13  *  http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf
14  *
15  *  Copyright (C) 2006-2007 Shem Multinymous <multinymous@gmail.com>
16  *
17  *  This program is free software; you can redistribute it and/or modify
18  *  it under the terms of the GNU General Public License as published by
19  *  the Free Software Foundation; either version 2 of the License, or
20  *  (at your option) any later version.
21  *
22  *  This program is distributed in the hope that it will be useful,
23  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  *  GNU General Public License for more details.
26  *
27  *  You should have received a copy of the GNU General Public License
28  *  along with this program; if not, write to the Free Software
29  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  */
31
32 #include <linux/kernel.h>
33 #include <linux/module.h>
34 #include <linux/dmi.h>
35 #include <linux/ioport.h>
36 #include <linux/delay.h>
37 #include "thinkpad_ec.h"
38 #include <linux/jiffies.h>
39 #include <asm/io.h>
40
41 #include <linux/version.h>
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
43         #include <asm/semaphore.h>
44 #else
45         #include <linux/semaphore.h>
46 #endif
47
48 #define TP_VERSION "0.41"
49
50 MODULE_AUTHOR("Shem Multinymous");
51 MODULE_DESCRIPTION("ThinkPad embedded controller hardware access");
52 MODULE_VERSION(TP_VERSION);
53 MODULE_LICENSE("GPL");
54
55 /* IO ports used by embedded controller LPC channel 3: */
56 #define TPC_BASE_PORT 0x1600
57 #define TPC_NUM_PORTS 0x20
58 #define TPC_STR3_PORT 0x1604  /* Reads H8S EC register STR3 */
59 #define TPC_TWR0_PORT  0x1610 /* Mapped to H8S EC register TWR0MW/SW  */
60 #define TPC_TWR15_PORT 0x161F /* Mapped to H8S EC register TWR15. */
61   /* (and port TPC_TWR0_PORT+i is mapped to H8S reg TWRi for 0<i<16) */
62
63 /* H8S STR3 status flags (see "H8S/2104B Group Hardware Manual" p.549) */
64 #define H8S_STR3_IBF3B 0x80  /* Bidi. Data Register Input Buffer Full */
65 #define H8S_STR3_OBF3B 0x40  /* Bidi. Data Register Output Buffer Full */
66 #define H8S_STR3_MWMF  0x20  /* Master Write Mode Flag */
67 #define H8S_STR3_SWMF  0x10  /* Slave Write Mode Flag */
68 #define H8S_STR3_MASK  0xF0  /* All bits we care about in STR3 */
69
70 /* Timeouts and retries */
71 #define TPC_READ_RETRIES     150
72 #define TPC_READ_NDELAY      500
73 #define TPC_REQUEST_RETRIES 1000
74 #define TPC_REQUEST_NDELAY    10
75 #define TPC_PREFETCH_TIMEOUT   (HZ/10)  /* invalidate prefetch after 0.1sec */
76
77 /* A few macros for printk()ing: */
78 #define MSG_FMT(fmt, args...) \
79   "thinkpad_ec: %s: " fmt "\n", __func__, ## args
80 #define REQ_FMT(msg, code) \
81   MSG_FMT("%s: (0x%02x:0x%02x)->0x%02x", \
82           msg, args->val[0x0], args->val[0xF], code)
83
84 /* State of request prefetching: */
85 static u8 prefetch_arg0, prefetch_argF;           /* Args of last prefetch */
86 static u64 prefetch_jiffies;                      /* time of prefetch, or: */
87 #define TPC_PREFETCH_NONE   INITIAL_JIFFIES       /*   No prefetch */
88 #define TPC_PREFETCH_JUNK   (INITIAL_JIFFIES+1)   /*   Ignore prefetch */
89
90 /* Locking: */
91 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
92 static DECLARE_MUTEX(thinkpad_ec_mutex);
93 #else
94 static DEFINE_SEMAPHORE(thinkpad_ec_mutex);
95 #endif
96
97 /* Kludge in case the ACPI DSDT reserves the ports we need. */
98 static int force_io;    /* Willing to do IO to ports we couldn't reserve? */
99 static int reserved_io; /* Successfully reserved the ports? */
100 module_param_named(force_io, force_io, bool, 0600);
101 MODULE_PARM_DESC(force_io, "Force IO even if region already reserved (0=off, 1=on)");
102
103 /**
104  * thinkpad_ec_lock - get lock on the ThinkPad EC
105  *
106  * Get exclusive lock for accesing the ThinkPad embedded controller LPC3
107  * interface. Returns 0 iff lock acquired.
108  */
109 int thinkpad_ec_lock(void)
110 {
111         int ret;
112         ret = down_interruptible(&thinkpad_ec_mutex);
113         return ret;
114 }
115 EXPORT_SYMBOL_GPL(thinkpad_ec_lock);
116
117 /**
118  * thinkpad_ec_try_lock - try getting lock on the ThinkPad EC
119  *
120  * Try getting an exclusive lock for accesing the ThinkPad embedded
121  * controller LPC3. Returns immediately if lock is not available; neither
122  * blocks nor sleeps. Returns 0 iff lock acquired .
123  */
124 int thinkpad_ec_try_lock(void)
125 {
126         return down_trylock(&thinkpad_ec_mutex);
127 }
128 EXPORT_SYMBOL_GPL(thinkpad_ec_try_lock);
129
130 /**
131  * thinkpad_ec_unlock - release lock on ThinkPad EC
132  *
133  * Release a previously acquired exclusive lock on the ThinkPad ebmedded
134  * controller LPC3 interface.
135  */
136 void thinkpad_ec_unlock(void)
137 {
138         up(&thinkpad_ec_mutex);
139 }
140 EXPORT_SYMBOL_GPL(thinkpad_ec_unlock);
141
142 /**
143  * thinkpad_ec_request_row - tell embedded controller to prepare a row
144  * @args Input register arguments
145  *
146  * Requests a data row by writing to H8S LPC registers TRW0 through TWR15 (or
147  * a subset thereof) following the protocol prescribed by the "H8S/2104B Group
148  * Hardware Manual". Does sanity checks via status register STR3.
149  */
150 static int thinkpad_ec_request_row(const struct thinkpad_ec_row *args)
151 {
152         u8 str3;
153         int i;
154
155         /* EC protocol requires write to TWR0 (function code): */
156         if (!(args->mask & 0x0001)) {
157                 printk(KERN_ERR MSG_FMT("bad args->mask=0x%02x", args->mask));
158                 return -EINVAL;
159         }
160
161         /* Check initial STR3 status: */
162         str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
163         if (str3 & H8S_STR3_OBF3B) { /* data already pending */
164                 inb(TPC_TWR15_PORT); /* marks end of previous transaction */
165                 if (prefetch_jiffies == TPC_PREFETCH_NONE)
166                         printk(KERN_WARNING REQ_FMT(
167                                "EC has result from unrequested transaction",
168                                str3));
169                 return -EBUSY; /* EC will be ready in a few usecs */
170         } else if (str3 == H8S_STR3_SWMF) { /* busy with previous request */
171                 if (prefetch_jiffies == TPC_PREFETCH_NONE)
172                         printk(KERN_WARNING REQ_FMT(
173                                "EC is busy with unrequested transaction",
174                                str3));
175                 return -EBUSY; /* data will be pending in a few usecs */
176         } else if (str3 != 0x00) { /* unexpected status? */
177                 printk(KERN_WARNING REQ_FMT("unexpected initial STR3", str3));
178                 return -EIO;
179         }
180
181         /* Send TWR0MW: */
182         outb(args->val[0], TPC_TWR0_PORT);
183         str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
184         if (str3 != H8S_STR3_MWMF) { /* not accepted? */
185                 printk(KERN_WARNING REQ_FMT("arg0 rejected", str3));
186                 return -EIO;
187         }
188
189         /* Send TWR1 through TWR14: */
190         for (i = 1; i < TP_CONTROLLER_ROW_LEN-1; i++)
191                 if ((args->mask>>i)&1)
192                         outb(args->val[i], TPC_TWR0_PORT+i);
193
194         /* Send TWR15 (default to 0x01). This marks end of command. */
195         outb((args->mask & 0x8000) ? args->val[0xF] : 0x01, TPC_TWR15_PORT);
196
197         /* Wait until EC starts writing its reply (~60ns on average).
198          * Releasing locks before this happens may cause an EC hang
199          * due to firmware bug!
200          */
201         for (i = 0; i < TPC_REQUEST_RETRIES; i++) {
202                 str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
203                 if (str3 & H8S_STR3_SWMF) /* EC started replying */
204                         return 0;
205                 else if (!(str3 & ~(H8S_STR3_IBF3B|H8S_STR3_MWMF)))
206                         /* Normal progress (the EC hasn't seen the request
207                          * yet, or is processing it). Wait it out. */
208                         ndelay(TPC_REQUEST_NDELAY);
209                 else { /* weird EC status */
210                         printk(KERN_WARNING
211                                REQ_FMT("bad end STR3", str3));
212                         return -EIO;
213                 }
214         }
215         printk(KERN_WARNING REQ_FMT("EC is mysteriously silent", str3));
216         return -EIO;
217 }
218
219 /**
220  * thinkpad_ec_read_data - read pre-requested row-data from EC
221  * @args Input register arguments of pre-requested rows
222  * @data Output register values
223  *
224  * Reads current row data from the controller, assuming it's already
225  * requested. Follows the H8S spec for register access and status checks.
226  */
227 static int thinkpad_ec_read_data(const struct thinkpad_ec_row *args,
228                                  struct thinkpad_ec_row *data)
229 {
230         int i;
231         u8 str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
232         /* Once we make a request, STR3 assumes the sequence of values listed
233          * in the following 'if' as it reads the request and writes its data.
234          * It takes about a few dozen nanosecs total, with very high variance.
235          */
236         if (str3 == (H8S_STR3_IBF3B|H8S_STR3_MWMF) ||
237             str3 == 0x00 ||  /* the 0x00 is indistinguishable from idle EC! */
238             str3 == H8S_STR3_SWMF)
239                 return -EBUSY; /* not ready yet */
240         /* Finally, the EC signals output buffer full: */
241         if (str3 != (H8S_STR3_OBF3B|H8S_STR3_SWMF)) {
242                 printk(KERN_WARNING
243                        REQ_FMT("bad initial STR3", str3));
244                 return -EIO;
245         }
246
247         /* Read first byte (signals start of read transactions): */
248         data->val[0] = inb(TPC_TWR0_PORT);
249         /* Optionally read 14 more bytes: */
250         for (i = 1; i < TP_CONTROLLER_ROW_LEN-1; i++)
251                 if ((data->mask >> i)&1)
252                         data->val[i] = inb(TPC_TWR0_PORT+i);
253         /* Read last byte from 0x161F (signals end of read transaction): */
254         data->val[0xF] = inb(TPC_TWR15_PORT);
255
256         /* Readout still pending? */
257         str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK;
258         if (str3 & H8S_STR3_OBF3B)
259                 printk(KERN_WARNING
260                        REQ_FMT("OBF3B=1 after read", str3));
261         /* If port 0x161F returns 0x80 too often, the EC may lock up. Warn: */
262         if (data->val[0xF] == 0x80)
263                 printk(KERN_WARNING
264                        REQ_FMT("0x161F reports error", data->val[0xF]));
265         return 0;
266 }
267
268 /**
269  * thinkpad_ec_is_row_fetched - is the given row currently prefetched?
270  *
271  * To keep things simple we compare only the first and last args;
272  * this suffices for all known cases.
273  */
274 static int thinkpad_ec_is_row_fetched(const struct thinkpad_ec_row *args)
275 {
276         return (prefetch_jiffies != TPC_PREFETCH_NONE) &&
277                (prefetch_jiffies != TPC_PREFETCH_JUNK) &&
278                (prefetch_arg0 == args->val[0]) &&
279                (prefetch_argF == args->val[0xF]) &&
280                (get_jiffies_64() < prefetch_jiffies + TPC_PREFETCH_TIMEOUT);
281 }
282
283 /**
284  * thinkpad_ec_read_row - request and read data from ThinkPad EC
285  * @args Input register arguments
286  * @data Output register values
287  *
288  * Read a data row from the ThinkPad embedded controller LPC3 interface.
289  * Does fetching and retrying if needed. The row is specified by an
290  * array of 16 bytes, some of which may be undefined (but the first is
291  * mandatory). These bytes are given in @args->val[], where @args->val[i] is
292  * used iff (@args->mask>>i)&1). The resulting row data is stored in
293  * @data->val[], but is only guaranteed to be valid for indices corresponding
294  * to set bit in @data->mask. That is, if @data->mask&(1<<i)==0 then
295  * @data->val[i] is undefined.
296  *
297  * Returns -EBUSY on transient error and -EIO on abnormal condition.
298  * Caller must hold controller lock.
299  */
300 int thinkpad_ec_read_row(const struct thinkpad_ec_row *args,
301                          struct thinkpad_ec_row *data)
302 {
303         int retries, ret;
304
305         if (thinkpad_ec_is_row_fetched(args))
306                 goto read_row; /* already requested */
307
308         /* Request the row */
309         for (retries = 0; retries < TPC_READ_RETRIES; ++retries) {
310                 ret = thinkpad_ec_request_row(args);
311                 if (!ret)
312                         goto read_row;
313                 if (ret != -EBUSY)
314                         break;
315                 ndelay(TPC_READ_NDELAY);
316         }
317         printk(KERN_ERR REQ_FMT("failed requesting row", ret));
318         goto out;
319
320 read_row:
321         /* Read the row's data */
322         for (retries = 0; retries < TPC_READ_RETRIES; ++retries) {
323                 ret = thinkpad_ec_read_data(args, data);
324                 if (!ret)
325                         goto out;
326                 if (ret != -EBUSY)
327                         break;
328                 ndelay(TPC_READ_NDELAY);
329         }
330
331         printk(KERN_ERR REQ_FMT("failed waiting for data", ret));
332
333 out:
334         prefetch_jiffies = TPC_PREFETCH_JUNK;
335         return ret;
336 }
337 EXPORT_SYMBOL_GPL(thinkpad_ec_read_row);
338
339 /**
340  * thinkpad_ec_try_read_row - try reading prefetched data from ThinkPad EC
341  * @args Input register arguments
342  * @data Output register values
343  *
344  * Try reading a data row from the ThinkPad embedded controller LPC3
345  * interface, if this raw was recently prefetched using
346  * thinkpad_ec_prefetch_row(). Does not fetch, retry or block.
347  * The parameters have the same meaning as in thinkpad_ec_read_row().
348  *
349  * Returns -EBUSY is data not ready and -ENODATA if row not prefetched.
350  * Caller must hold controller lock.
351  */
352 int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args,
353                              struct thinkpad_ec_row *data)
354 {
355         int ret;
356         if (!thinkpad_ec_is_row_fetched(args)) {
357                 ret = -ENODATA;
358         } else {
359                 ret = thinkpad_ec_read_data(args, data);
360                 if (!ret)
361                         prefetch_jiffies = TPC_PREFETCH_NONE; /* eaten up */
362         }
363         return ret;
364 }
365 EXPORT_SYMBOL_GPL(thinkpad_ec_try_read_row);
366
367 /**
368  * thinkpad_ec_prefetch_row - prefetch data from ThinkPad EC
369  * @args Input register arguments
370  *
371  * Prefetch a data row from the ThinkPad embedded controller LCP3
372  * interface. A subsequent call to thinkpad_ec_read_row() with the
373  * same arguments will be faster, and a subsequent call to
374  * thinkpad_ec_try_read_row() stands a good chance of succeeding if
375  * done neither too soon nor too late. See
376  * thinkpad_ec_read_row() for the meaning of @args.
377  *
378  * Returns -EBUSY on transient error and -EIO on abnormal condition.
379  * Caller must hold controller lock.
380  */
381 int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args)
382 {
383         int ret;
384         ret = thinkpad_ec_request_row(args);
385         if (ret) {
386                 prefetch_jiffies = TPC_PREFETCH_JUNK;
387         } else {
388                 prefetch_jiffies = get_jiffies_64();
389                 prefetch_arg0 = args->val[0x0];
390                 prefetch_argF = args->val[0xF];
391         }
392         return ret;
393 }
394 EXPORT_SYMBOL_GPL(thinkpad_ec_prefetch_row);
395
396 /**
397  * thinkpad_ec_invalidate - invalidate prefetched ThinkPad EC data
398  *
399  * Invalidate the data prefetched via thinkpad_ec_prefetch_row() from the
400  * ThinkPad embedded controller LPC3 interface.
401  * Must be called before unlocking by any code that accesses the controller
402  * ports directly.
403  */
404 void thinkpad_ec_invalidate(void)
405 {
406         prefetch_jiffies = TPC_PREFETCH_JUNK;
407 }
408 EXPORT_SYMBOL_GPL(thinkpad_ec_invalidate);
409
410
411 /*** Checking for EC hardware ***/
412
413 /**
414  * thinkpad_ec_test - verify the EC is present and follows protocol
415  *
416  * Ensure the EC LPC3 channel really works on this machine by making
417  * an EC request and seeing if the EC follows the documented H8S protocol.
418  * The requested row just reads battery status, so it should be harmless to
419  * access it (on a correct EC).
420  * This test writes to IO ports, so execute only after checking DMI.
421  */
422 static int __init thinkpad_ec_test(void)
423 {
424         int ret;
425         const struct thinkpad_ec_row args = /* battery 0 basic status */
426           { .mask = 0x8001, .val = {0x01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00} };
427         struct thinkpad_ec_row data = { .mask = 0x0000 };
428         ret = thinkpad_ec_lock();
429         if (ret)
430                 return ret;
431         ret = thinkpad_ec_read_row(&args, &data);
432         thinkpad_ec_unlock();
433         return ret;
434 }
435
436 /* Search all DMI device names of a given type for a substring */
437 static int __init dmi_find_substring(int type, const char *substr)
438 {
439         const struct dmi_device *dev = NULL;
440         while ((dev = dmi_find_device(type, NULL, dev))) {
441                 if (strstr(dev->name, substr))
442                         return 1;
443         }
444         return 0;
445 }
446
447 #define TP_DMI_MATCH(vendor,model)      {               \
448         .ident = vendor " " model,                      \
449         .matches = {                                    \
450                 DMI_MATCH(DMI_BOARD_VENDOR, vendor),    \
451                 DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
452         }                                               \
453 }
454
455 /* Check DMI for existence of ThinkPad embedded controller */
456 static int __init check_dmi_for_ec(void)
457 {
458         /* A few old models that have a good EC but don't report it in DMI */
459         struct dmi_system_id tp_whitelist[] = {
460                 TP_DMI_MATCH("IBM", "ThinkPad A30"),
461                 TP_DMI_MATCH("IBM", "ThinkPad T23"),
462                 TP_DMI_MATCH("IBM", "ThinkPad X24"),
463                 TP_DMI_MATCH("LENOVO", "ThinkPad"),
464                 { .ident = NULL }
465         };
466         return dmi_find_substring(DMI_DEV_TYPE_OEM_STRING,
467                                   "IBM ThinkPad Embedded Controller") ||
468                dmi_check_system(tp_whitelist);
469 }
470
471 /*** Init and cleanup ***/
472
473 static int __init thinkpad_ec_init(void)
474 {
475         if (!check_dmi_for_ec()) {
476                 printk(KERN_WARNING
477                        "thinkpad_ec: no ThinkPad embedded controller!\n");
478                 return -ENODEV;
479         }
480
481         if (request_region(TPC_BASE_PORT, TPC_NUM_PORTS, "thinkpad_ec")) {
482                 reserved_io = 1;
483         } else {
484                 printk(KERN_ERR "thinkpad_ec: cannot claim IO ports %#x-%#x... ",
485                        TPC_BASE_PORT,
486                        TPC_BASE_PORT + TPC_NUM_PORTS - 1);
487                 if (force_io) {
488                         printk("forcing use of unreserved IO ports.\n");
489                 } else {
490                         printk("consider using force_io=1.\n");
491                         return -ENXIO;
492                 }
493         }
494         prefetch_jiffies = TPC_PREFETCH_JUNK;
495         if (thinkpad_ec_test()) {
496                 printk(KERN_ERR "thinkpad_ec: initial ec test failed\n");
497                 if (reserved_io)
498                         release_region(TPC_BASE_PORT, TPC_NUM_PORTS);
499                 return -ENXIO;
500         }
501         printk(KERN_INFO "thinkpad_ec: thinkpad_ec " TP_VERSION " loaded.\n");
502         return 0;
503 }
504
505 static void __exit thinkpad_ec_exit(void)
506 {
507         if (reserved_io)
508                 release_region(TPC_BASE_PORT, TPC_NUM_PORTS);
509         printk(KERN_INFO "thinkpad_ec: unloaded.\n");
510 }
511
512 module_init(thinkpad_ec_init);
513 module_exit(thinkpad_ec_exit);