]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/platform/x86/compal-laptop.c
Merge tag 'jfs-3.12' of git://github.com/kleikamp/linux-shaggy
[karo-tx-linux.git] / drivers / platform / x86 / compal-laptop.c
1 /*-*-linux-c-*-*/
2
3 /*
4   Copyright (C) 2008 Cezary Jackiewicz <cezary.jackiewicz (at) gmail.com>
5
6   based on MSI driver
7
8   Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23   02110-1301, USA.
24  */
25
26 /*
27  * compal-laptop.c - Compal laptop support.
28  *
29  * This driver exports a few files in /sys/devices/platform/compal-laptop/:
30  *   wake_up_XXX   Whether or not we listen to such wake up events (rw)
31  *
32  * In addition to these platform device attributes the driver
33  * registers itself in the Linux backlight control, power_supply, rfkill
34  * and hwmon subsystem and is available to userspace under:
35  *
36  *   /sys/class/backlight/compal-laptop/
37  *   /sys/class/power_supply/compal-laptop/
38  *   /sys/class/rfkill/rfkillX/
39  *   /sys/class/hwmon/hwmonX/
40  *
41  * Notes on the power_supply battery interface:
42  *   - the "minimum" design voltage is *the* design voltage
43  *   - the ambient temperature is the average battery temperature
44  *     and the value is an educated guess (see commented code below)
45  *
46  *
47  * This driver might work on other laptops produced by Compal. If you
48  * want to try it you can pass force=1 as argument to the module which
49  * will force it to load even when the DMI data doesn't identify the
50  * laptop as compatible.
51  *
52  * Lots of data available at:
53  * http://service1.marasst.com/Compal/JHL90_91/Service%20Manual/
54  * JHL90%20service%20manual-Final-0725.pdf
55  *
56  *
57  *
58  * Support for the Compal JHL90 added by Roald Frederickx
59  * (roald.frederickx@gmail.com):
60  * Driver got large revision. Added functionalities: backlight
61  * power, wake_on_XXX, a hwmon and power_supply interface.
62  *
63  * In case this gets merged into the kernel source: I want to dedicate this
64  * to Kasper Meerts, the awesome guy who showed me Linux and C!
65  */
66
67 /* NOTE: currently the wake_on_XXX, hwmon and power_supply interfaces are
68  * only enabled on a JHL90 board until it is verified that they work on the
69  * other boards too.  See the extra_features variable. */
70
71 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
72
73 #include <linux/module.h>
74 #include <linux/kernel.h>
75 #include <linux/init.h>
76 #include <linux/acpi.h>
77 #include <linux/dmi.h>
78 #include <linux/backlight.h>
79 #include <linux/platform_device.h>
80 #include <linux/rfkill.h>
81 #include <linux/hwmon.h>
82 #include <linux/hwmon-sysfs.h>
83 #include <linux/power_supply.h>
84 #include <linux/fb.h>
85
86
87 /* ======= */
88 /* Defines */
89 /* ======= */
90 #define DRIVER_NAME "compal-laptop"
91 #define DRIVER_VERSION  "0.2.7"
92
93 #define BACKLIGHT_LEVEL_ADDR            0xB9
94 #define BACKLIGHT_LEVEL_MAX             7
95 #define BACKLIGHT_STATE_ADDR            0x59
96 #define BACKLIGHT_STATE_ON_DATA         0xE1
97 #define BACKLIGHT_STATE_OFF_DATA        0xE2
98
99 #define WAKE_UP_ADDR                    0xA4
100 #define WAKE_UP_PME                     (1 << 0)
101 #define WAKE_UP_MODEM                   (1 << 1)
102 #define WAKE_UP_LAN                     (1 << 2)
103 #define WAKE_UP_WLAN                    (1 << 4)
104 #define WAKE_UP_KEY                     (1 << 6)
105 #define WAKE_UP_MOUSE                   (1 << 7)
106
107 #define WIRELESS_ADDR                   0xBB
108 #define WIRELESS_WLAN                   (1 << 0)
109 #define WIRELESS_BT                     (1 << 1)
110 #define WIRELESS_WLAN_EXISTS            (1 << 2)
111 #define WIRELESS_BT_EXISTS              (1 << 3)
112 #define WIRELESS_KILLSWITCH             (1 << 4)
113
114 #define PWM_ADDRESS                     0x46
115 #define PWM_DISABLE_ADDR                0x59
116 #define PWM_DISABLE_DATA                0xA5
117 #define PWM_ENABLE_ADDR                 0x59
118 #define PWM_ENABLE_DATA                 0xA8
119
120 #define FAN_ADDRESS                     0x46
121 #define FAN_DATA                        0x81
122 #define FAN_FULL_ON_CMD                 0x59 /* Doesn't seem to work. Just */
123 #define FAN_FULL_ON_ENABLE              0x76 /* force the pwm signal to its */
124 #define FAN_FULL_ON_DISABLE             0x77 /* maximum value instead */
125
126 #define TEMP_CPU                        0xB0
127 #define TEMP_CPU_LOCAL                  0xB1
128 #define TEMP_CPU_DTS                    0xB5
129 #define TEMP_NORTHBRIDGE                0xB6
130 #define TEMP_VGA                        0xB4
131 #define TEMP_SKIN                       0xB2
132
133 #define BAT_MANUFACTURER_NAME_ADDR      0x10
134 #define BAT_MANUFACTURER_NAME_LEN       9
135 #define BAT_MODEL_NAME_ADDR             0x19
136 #define BAT_MODEL_NAME_LEN              6
137 #define BAT_SERIAL_NUMBER_ADDR          0xC4
138 #define BAT_SERIAL_NUMBER_LEN           5
139 #define BAT_CHARGE_NOW                  0xC2
140 #define BAT_CHARGE_DESIGN               0xCA
141 #define BAT_VOLTAGE_NOW                 0xC6
142 #define BAT_VOLTAGE_DESIGN              0xC8
143 #define BAT_CURRENT_NOW                 0xD0
144 #define BAT_CURRENT_AVG                 0xD2
145 #define BAT_POWER                       0xD4
146 #define BAT_CAPACITY                    0xCE
147 #define BAT_TEMP                        0xD6
148 #define BAT_TEMP_AVG                    0xD7
149 #define BAT_STATUS0                     0xC1
150 #define BAT_STATUS1                     0xF0
151 #define BAT_STATUS2                     0xF1
152 #define BAT_STOP_CHARGE1                0xF2
153 #define BAT_STOP_CHARGE2                0xF3
154
155 #define BAT_S0_DISCHARGE                (1 << 0)
156 #define BAT_S0_DISCHRG_CRITICAL         (1 << 2)
157 #define BAT_S0_LOW                      (1 << 3)
158 #define BAT_S0_CHARGING                 (1 << 1)
159 #define BAT_S0_AC                       (1 << 7)
160 #define BAT_S1_EXISTS                   (1 << 0)
161 #define BAT_S1_FULL                     (1 << 1)
162 #define BAT_S1_EMPTY                    (1 << 2)
163 #define BAT_S1_LiION_OR_NiMH            (1 << 7)
164 #define BAT_S2_LOW_LOW                  (1 << 0)
165 #define BAT_STOP_CHRG1_BAD_CELL         (1 << 1)
166 #define BAT_STOP_CHRG1_COMM_FAIL        (1 << 2)
167 #define BAT_STOP_CHRG1_OVERVOLTAGE      (1 << 6)
168 #define BAT_STOP_CHRG1_OVERTEMPERATURE  (1 << 7)
169
170
171 /* ======= */
172 /* Structs */
173 /* ======= */
174 struct compal_data{
175         /* Fan control */
176         struct device *hwmon_dev;
177         int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by moterboard */
178         unsigned char curr_pwm;
179
180         /* Power supply */
181         struct power_supply psy;
182         struct power_supply_info psy_info;
183         char bat_model_name[BAT_MODEL_NAME_LEN + 1];
184         char bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN + 1];
185         char bat_serial_number[BAT_SERIAL_NUMBER_LEN + 1];
186 };
187
188
189 /* =============== */
190 /* General globals */
191 /* =============== */
192 static bool force;
193 module_param(force, bool, 0);
194 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
195
196 /* Support for the wake_on_XXX, hwmon and power_supply interface. Currently
197  * only gets enabled on a JHL90 board. Might work with the others too */
198 static bool extra_features;
199
200 /* Nasty stuff. For some reason the fan control is very un-linear.  I've
201  * come up with these values by looping through the possible inputs and
202  * watching the output of address 0x4F (do an ec_transaction writing 0x33
203  * into 0x4F and read a few bytes from the output, like so:
204  *      u8 writeData = 0x33;
205  *      ec_transaction(0x4F, &writeData, 1, buffer, 32);
206  * That address is labeled "fan1 table information" in the service manual.
207  * It should be clear which value in 'buffer' changes). This seems to be
208  * related to fan speed. It isn't a proper 'realtime' fan speed value
209  * though, because physically stopping or speeding up the fan doesn't
210  * change it. It might be the average voltage or current of the pwm output.
211  * Nevertheless, it is more fine-grained than the actual RPM reading */
212 static const unsigned char pwm_lookup_table[256] = {
213         0, 0, 0, 1, 1, 1, 2, 253, 254, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6,
214         7, 7, 7, 8, 86, 86, 9, 9, 9, 10, 10, 10, 11, 92, 92, 12, 12, 95,
215         13, 66, 66, 14, 14, 98, 15, 15, 15, 16, 16, 67, 17, 17, 72, 18, 70,
216         75, 19, 90, 90, 73, 73, 73, 21, 21, 91, 91, 91, 96, 23, 94, 94, 94,
217         94, 94, 94, 94, 94, 94, 94, 141, 141, 238, 223, 192, 139, 139, 139,
218         139, 139, 142, 142, 142, 142, 142, 78, 78, 78, 78, 78, 76, 76, 76,
219         76, 76, 79, 79, 79, 79, 79, 79, 79, 20, 20, 20, 20, 20, 22, 22, 22,
220         22, 22, 24, 24, 24, 24, 24, 24, 219, 219, 219, 219, 219, 219, 219,
221         219, 27, 27, 188, 188, 28, 28, 28, 29, 186, 186, 186, 186, 186,
222         186, 186, 186, 186, 186, 31, 31, 31, 31, 31, 32, 32, 32, 41, 33,
223         33, 33, 33, 33, 252, 252, 34, 34, 34, 43, 35, 35, 35, 36, 36, 38,
224         206, 206, 206, 206, 206, 206, 206, 206, 206, 37, 37, 37, 46, 46,
225         47, 47, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 48, 48,
226         48, 48, 48, 40, 40, 40, 49, 42, 42, 42, 42, 42, 42, 42, 42, 44,
227         189, 189, 189, 189, 54, 54, 45, 45, 45, 45, 45, 45, 45, 45, 251,
228         191, 199, 199, 199, 199, 199, 215, 215, 215, 215, 187, 187, 187,
229         187, 187, 193, 50
230 };
231
232
233
234
235 /* ========================= */
236 /* Hardware access functions */
237 /* ========================= */
238 /* General access */
239 static u8 ec_read_u8(u8 addr)
240 {
241         u8 value;
242         ec_read(addr, &value);
243         return value;
244 }
245
246 static s8 ec_read_s8(u8 addr)
247 {
248         return (s8)ec_read_u8(addr);
249 }
250
251 static u16 ec_read_u16(u8 addr)
252 {
253         int hi, lo;
254         lo = ec_read_u8(addr);
255         hi = ec_read_u8(addr + 1);
256         return (hi << 8) + lo;
257 }
258
259 static s16 ec_read_s16(u8 addr)
260 {
261         return (s16) ec_read_u16(addr);
262 }
263
264 static void ec_read_sequence(u8 addr, u8 *buf, int len)
265 {
266         int i;
267         for (i = 0; i < len; i++)
268                 ec_read(addr + i, buf + i);
269 }
270
271
272 /* Backlight access */
273 static int set_backlight_level(int level)
274 {
275         if (level < 0 || level > BACKLIGHT_LEVEL_MAX)
276                 return -EINVAL;
277
278         ec_write(BACKLIGHT_LEVEL_ADDR, level);
279
280         return 0;
281 }
282
283 static int get_backlight_level(void)
284 {
285         return (int) ec_read_u8(BACKLIGHT_LEVEL_ADDR);
286 }
287
288 static void set_backlight_state(bool on)
289 {
290         u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA;
291         ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0);
292 }
293
294
295 /* Fan control access */
296 static void pwm_enable_control(void)
297 {
298         unsigned char writeData = PWM_ENABLE_DATA;
299         ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0);
300 }
301
302 static void pwm_disable_control(void)
303 {
304         unsigned char writeData = PWM_DISABLE_DATA;
305         ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0);
306 }
307
308 static void set_pwm(int pwm)
309 {
310         ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0);
311 }
312
313 static int get_fan_rpm(void)
314 {
315         u8 value, data = FAN_DATA;
316         ec_transaction(FAN_ADDRESS, &data, 1, &value, 1);
317         return 100 * (int)value;
318 }
319
320
321
322
323 /* =================== */
324 /* Interface functions */
325 /* =================== */
326
327 /* Backlight interface */
328 static int bl_get_brightness(struct backlight_device *b)
329 {
330         return get_backlight_level();
331 }
332
333 static int bl_update_status(struct backlight_device *b)
334 {
335         int ret = set_backlight_level(b->props.brightness);
336         if (ret)
337                 return ret;
338
339         set_backlight_state((b->props.power == FB_BLANK_UNBLANK)
340                 &&    !(b->props.state & BL_CORE_SUSPENDED)
341                 &&    !(b->props.state & BL_CORE_FBBLANK));
342         return 0;
343 }
344
345 static const struct backlight_ops compalbl_ops = {
346         .get_brightness = bl_get_brightness,
347         .update_status  = bl_update_status,
348 };
349
350
351 /* Wireless interface */
352 static int compal_rfkill_set(void *data, bool blocked)
353 {
354         unsigned long radio = (unsigned long) data;
355         u8 result = ec_read_u8(WIRELESS_ADDR);
356         u8 value;
357
358         if (!blocked)
359                 value = (u8) (result | radio);
360         else
361                 value = (u8) (result & ~radio);
362         ec_write(WIRELESS_ADDR, value);
363
364         return 0;
365 }
366
367 static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
368 {
369         u8 result = ec_read_u8(WIRELESS_ADDR);
370         bool hw_blocked = !(result & WIRELESS_KILLSWITCH);
371         rfkill_set_hw_state(rfkill, hw_blocked);
372 }
373
374 static const struct rfkill_ops compal_rfkill_ops = {
375         .poll = compal_rfkill_poll,
376         .set_block = compal_rfkill_set,
377 };
378
379
380 /* Wake_up interface */
381 #define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK)                      \
382 static ssize_t NAME##_show(struct device *dev,                          \
383         struct device_attribute *attr, char *buf)                       \
384 {                                                                       \
385         return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0));  \
386 }                                                                       \
387 static ssize_t NAME##_store(struct device *dev,                         \
388         struct device_attribute *attr, const char *buf, size_t count)   \
389 {                                                                       \
390         int state;                                                      \
391         u8 old_val = ec_read_u8(ADDR);                                  \
392         if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \
393                 return -EINVAL;                                         \
394         ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK));   \
395         return count;                                                   \
396 }
397
398 SIMPLE_MASKED_STORE_SHOW(wake_up_pme,   WAKE_UP_ADDR, WAKE_UP_PME)
399 SIMPLE_MASKED_STORE_SHOW(wake_up_modem, WAKE_UP_ADDR, WAKE_UP_MODEM)
400 SIMPLE_MASKED_STORE_SHOW(wake_up_lan,   WAKE_UP_ADDR, WAKE_UP_LAN)
401 SIMPLE_MASKED_STORE_SHOW(wake_up_wlan,  WAKE_UP_ADDR, WAKE_UP_WLAN)
402 SIMPLE_MASKED_STORE_SHOW(wake_up_key,   WAKE_UP_ADDR, WAKE_UP_KEY)
403 SIMPLE_MASKED_STORE_SHOW(wake_up_mouse, WAKE_UP_ADDR, WAKE_UP_MOUSE)
404
405
406 /* General hwmon interface */
407 static ssize_t hwmon_name_show(struct device *dev,
408                 struct device_attribute *attr, char *buf)
409 {
410         return sprintf(buf, "%s\n", DRIVER_NAME);
411 }
412
413
414 /* Fan control interface */
415 static ssize_t pwm_enable_show(struct device *dev,
416                 struct device_attribute *attr, char *buf)
417 {
418         struct compal_data *data = dev_get_drvdata(dev);
419         return sprintf(buf, "%d\n", data->pwm_enable);
420 }
421
422 static ssize_t pwm_enable_store(struct device *dev,
423                 struct device_attribute *attr, const char *buf, size_t count)
424 {
425         struct compal_data *data = dev_get_drvdata(dev);
426         long val;
427         int err;
428
429         err = kstrtol(buf, 10, &val);
430         if (err)
431                 return err;
432         if (val < 0)
433                 return -EINVAL;
434
435         data->pwm_enable = val;
436
437         switch (val) {
438         case 0:  /* Full speed */
439                 pwm_enable_control();
440                 set_pwm(255);
441                 break;
442         case 1:  /* As set by pwm1 */
443                 pwm_enable_control();
444                 set_pwm(data->curr_pwm);
445                 break;
446         default: /* Control by motherboard */
447                 pwm_disable_control();
448                 break;
449         }
450
451         return count;
452 }
453
454 static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
455                 char *buf)
456 {
457         struct compal_data *data = dev_get_drvdata(dev);
458         return sprintf(buf, "%hhu\n", data->curr_pwm);
459 }
460
461 static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
462                 const char *buf, size_t count)
463 {
464         struct compal_data *data = dev_get_drvdata(dev);
465         long val;
466         int err;
467
468         err = kstrtol(buf, 10, &val);
469         if (err)
470                 return err;
471         if (val < 0 || val > 255)
472                 return -EINVAL;
473
474         data->curr_pwm = val;
475
476         if (data->pwm_enable != 1)
477                 return count;
478         set_pwm(val);
479
480         return count;
481 }
482
483 static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
484                 char *buf)
485 {
486         return sprintf(buf, "%d\n", get_fan_rpm());
487 }
488
489
490 /* Temperature interface */
491 #define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL)        \
492 static ssize_t temp_##POSTFIX(struct device *dev,                       \
493                 struct device_attribute *attr, char *buf)               \
494 {                                                                       \
495         return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS));   \
496 }                                                                       \
497 static ssize_t label_##POSTFIX(struct device *dev,                      \
498                 struct device_attribute *attr, char *buf)               \
499 {                                                                       \
500         return sprintf(buf, "%s\n", LABEL);                             \
501 }
502
503 /* Labels as in service guide */
504 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu,        TEMP_CPU,        "CPU_TEMP");
505 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local,  TEMP_CPU_LOCAL,  "CPU_TEMP_LOCAL");
506 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS,    TEMP_CPU_DTS,    "CPU_DTS");
507 TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge");
508 TEMPERATURE_SHOW_TEMP_AND_LABEL(vga,        TEMP_VGA,        "VGA_TEMP");
509 TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN,       TEMP_SKIN,       "SKIN_TEMP90");
510
511
512 /* Power supply interface */
513 static int bat_status(void)
514 {
515         u8 status0 = ec_read_u8(BAT_STATUS0);
516         u8 status1 = ec_read_u8(BAT_STATUS1);
517
518         if (status0 & BAT_S0_CHARGING)
519                 return POWER_SUPPLY_STATUS_CHARGING;
520         if (status0 & BAT_S0_DISCHARGE)
521                 return POWER_SUPPLY_STATUS_DISCHARGING;
522         if (status1 & BAT_S1_FULL)
523                 return POWER_SUPPLY_STATUS_FULL;
524         return POWER_SUPPLY_STATUS_NOT_CHARGING;
525 }
526
527 static int bat_health(void)
528 {
529         u8 status = ec_read_u8(BAT_STOP_CHARGE1);
530
531         if (status & BAT_STOP_CHRG1_OVERTEMPERATURE)
532                 return POWER_SUPPLY_HEALTH_OVERHEAT;
533         if (status & BAT_STOP_CHRG1_OVERVOLTAGE)
534                 return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
535         if (status & BAT_STOP_CHRG1_BAD_CELL)
536                 return POWER_SUPPLY_HEALTH_DEAD;
537         if (status & BAT_STOP_CHRG1_COMM_FAIL)
538                 return POWER_SUPPLY_HEALTH_UNKNOWN;
539         return POWER_SUPPLY_HEALTH_GOOD;
540 }
541
542 static int bat_is_present(void)
543 {
544         u8 status = ec_read_u8(BAT_STATUS2);
545         return ((status & BAT_S1_EXISTS) != 0);
546 }
547
548 static int bat_technology(void)
549 {
550         u8 status = ec_read_u8(BAT_STATUS1);
551
552         if (status & BAT_S1_LiION_OR_NiMH)
553                 return POWER_SUPPLY_TECHNOLOGY_LION;
554         return POWER_SUPPLY_TECHNOLOGY_NiMH;
555 }
556
557 static int bat_capacity_level(void)
558 {
559         u8 status0 = ec_read_u8(BAT_STATUS0);
560         u8 status1 = ec_read_u8(BAT_STATUS1);
561         u8 status2 = ec_read_u8(BAT_STATUS2);
562
563         if (status0 & BAT_S0_DISCHRG_CRITICAL
564                         || status1 & BAT_S1_EMPTY
565                         || status2 & BAT_S2_LOW_LOW)
566                 return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
567         if (status0 & BAT_S0_LOW)
568                 return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
569         if (status1 & BAT_S1_FULL)
570                 return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
571         return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
572 }
573
574 static int bat_get_property(struct power_supply *psy,
575                                 enum power_supply_property psp,
576                                 union power_supply_propval *val)
577 {
578         struct compal_data *data;
579         data = container_of(psy, struct compal_data, psy);
580
581         switch (psp) {
582         case POWER_SUPPLY_PROP_STATUS:
583                 val->intval = bat_status();
584                 break;
585         case POWER_SUPPLY_PROP_HEALTH:
586                 val->intval = bat_health();
587                 break;
588         case POWER_SUPPLY_PROP_PRESENT:
589                 val->intval = bat_is_present();
590                 break;
591         case POWER_SUPPLY_PROP_TECHNOLOGY:
592                 val->intval = bat_technology();
593                 break;
594         case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: /* THE design voltage... */
595                 val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000;
596                 break;
597         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
598                 val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000;
599                 break;
600         case POWER_SUPPLY_PROP_CURRENT_NOW:
601                 val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000;
602                 break;
603         case POWER_SUPPLY_PROP_CURRENT_AVG:
604                 val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000;
605                 break;
606         case POWER_SUPPLY_PROP_POWER_NOW:
607                 val->intval = ec_read_u8(BAT_POWER) * 1000000;
608                 break;
609         case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
610                 val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000;
611                 break;
612         case POWER_SUPPLY_PROP_CHARGE_NOW:
613                 val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
614                 break;
615         case POWER_SUPPLY_PROP_CAPACITY:
616                 val->intval = ec_read_u8(BAT_CAPACITY);
617                 break;
618         case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
619                 val->intval = bat_capacity_level();
620                 break;
621         /* It smees that BAT_TEMP_AVG is a (2's complement?) value showing
622          * the number of degrees, whereas BAT_TEMP is somewhat more
623          * complicated. It looks like this is a negative nember with a
624          * 100/256 divider and an offset of 222. Both were determined
625          * experimentally by comparing BAT_TEMP and BAT_TEMP_AVG. */
626         case POWER_SUPPLY_PROP_TEMP:
627                 val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8;
628                 break;
629         case POWER_SUPPLY_PROP_TEMP_AMBIENT: /* Ambient, Avg, ... same thing */
630                 val->intval = ec_read_s8(BAT_TEMP_AVG) * 10;
631                 break;
632         /* Neither the model name nor manufacturer name work for me. */
633         case POWER_SUPPLY_PROP_MODEL_NAME:
634                 val->strval = data->bat_model_name;
635                 break;
636         case POWER_SUPPLY_PROP_MANUFACTURER:
637                 val->strval = data->bat_manufacturer_name;
638                 break;
639         case POWER_SUPPLY_PROP_SERIAL_NUMBER:
640                 val->strval = data->bat_serial_number;
641                 break;
642         default:
643                 break;
644         }
645         return 0;
646 }
647
648
649
650
651
652 /* ============== */
653 /* Driver Globals */
654 /* ============== */
655 static DEVICE_ATTR(wake_up_pme,
656                 0644, wake_up_pme_show,         wake_up_pme_store);
657 static DEVICE_ATTR(wake_up_modem,
658                 0644, wake_up_modem_show,       wake_up_modem_store);
659 static DEVICE_ATTR(wake_up_lan,
660                 0644, wake_up_lan_show, wake_up_lan_store);
661 static DEVICE_ATTR(wake_up_wlan,
662                 0644, wake_up_wlan_show,        wake_up_wlan_store);
663 static DEVICE_ATTR(wake_up_key,
664                 0644, wake_up_key_show, wake_up_key_store);
665 static DEVICE_ATTR(wake_up_mouse,
666                 0644, wake_up_mouse_show,       wake_up_mouse_store);
667
668 static SENSOR_DEVICE_ATTR(name,        S_IRUGO, hwmon_name_show,   NULL, 1);
669 static SENSOR_DEVICE_ATTR(fan1_input,  S_IRUGO, fan_show,          NULL, 1);
670 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu,          NULL, 1);
671 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local,    NULL, 1);
672 static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS,      NULL, 1);
673 static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge,  NULL, 1);
674 static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga,          NULL, 1);
675 static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN,         NULL, 1);
676 static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu,         NULL, 1);
677 static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local,   NULL, 1);
678 static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS,     NULL, 1);
679 static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL, 1);
680 static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, label_vga,         NULL, 1);
681 static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN,        NULL, 1);
682 static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store, 1);
683 static SENSOR_DEVICE_ATTR(pwm1_enable,
684                 S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store, 0);
685
686 static struct attribute *compal_attributes[] = {
687         &dev_attr_wake_up_pme.attr,
688         &dev_attr_wake_up_modem.attr,
689         &dev_attr_wake_up_lan.attr,
690         &dev_attr_wake_up_wlan.attr,
691         &dev_attr_wake_up_key.attr,
692         &dev_attr_wake_up_mouse.attr,
693         /* Maybe put the sensor-stuff in a separate hwmon-driver? That way,
694          * the hwmon sysfs won't be cluttered with the above files. */
695         &sensor_dev_attr_name.dev_attr.attr,
696         &sensor_dev_attr_pwm1_enable.dev_attr.attr,
697         &sensor_dev_attr_pwm1.dev_attr.attr,
698         &sensor_dev_attr_fan1_input.dev_attr.attr,
699         &sensor_dev_attr_temp1_input.dev_attr.attr,
700         &sensor_dev_attr_temp2_input.dev_attr.attr,
701         &sensor_dev_attr_temp3_input.dev_attr.attr,
702         &sensor_dev_attr_temp4_input.dev_attr.attr,
703         &sensor_dev_attr_temp5_input.dev_attr.attr,
704         &sensor_dev_attr_temp6_input.dev_attr.attr,
705         &sensor_dev_attr_temp1_label.dev_attr.attr,
706         &sensor_dev_attr_temp2_label.dev_attr.attr,
707         &sensor_dev_attr_temp3_label.dev_attr.attr,
708         &sensor_dev_attr_temp4_label.dev_attr.attr,
709         &sensor_dev_attr_temp5_label.dev_attr.attr,
710         &sensor_dev_attr_temp6_label.dev_attr.attr,
711         NULL
712 };
713
714 static struct attribute_group compal_attribute_group = {
715         .attrs = compal_attributes
716 };
717
718 static int compal_probe(struct platform_device *);
719 static int compal_remove(struct platform_device *);
720 static struct platform_driver compal_driver = {
721         .driver = {
722                 .name = DRIVER_NAME,
723                 .owner = THIS_MODULE,
724         },
725         .probe  = compal_probe,
726         .remove = compal_remove,
727 };
728
729 static enum power_supply_property compal_bat_properties[] = {
730         POWER_SUPPLY_PROP_STATUS,
731         POWER_SUPPLY_PROP_HEALTH,
732         POWER_SUPPLY_PROP_PRESENT,
733         POWER_SUPPLY_PROP_TECHNOLOGY,
734         POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
735         POWER_SUPPLY_PROP_VOLTAGE_NOW,
736         POWER_SUPPLY_PROP_CURRENT_NOW,
737         POWER_SUPPLY_PROP_CURRENT_AVG,
738         POWER_SUPPLY_PROP_POWER_NOW,
739         POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
740         POWER_SUPPLY_PROP_CHARGE_NOW,
741         POWER_SUPPLY_PROP_CAPACITY,
742         POWER_SUPPLY_PROP_CAPACITY_LEVEL,
743         POWER_SUPPLY_PROP_TEMP,
744         POWER_SUPPLY_PROP_TEMP_AMBIENT,
745         POWER_SUPPLY_PROP_MODEL_NAME,
746         POWER_SUPPLY_PROP_MANUFACTURER,
747         POWER_SUPPLY_PROP_SERIAL_NUMBER,
748 };
749
750 static struct backlight_device *compalbl_device;
751
752 static struct platform_device *compal_device;
753
754 static struct rfkill *wifi_rfkill;
755 static struct rfkill *bt_rfkill;
756
757
758
759
760
761 /* =================================== */
762 /* Initialization & clean-up functions */
763 /* =================================== */
764
765 static int dmi_check_cb(const struct dmi_system_id *id)
766 {
767         pr_info("Identified laptop model '%s'\n", id->ident);
768         extra_features = false;
769         return 1;
770 }
771
772 static int dmi_check_cb_extra(const struct dmi_system_id *id)
773 {
774         pr_info("Identified laptop model '%s', enabling extra features\n",
775                 id->ident);
776         extra_features = true;
777         return 1;
778 }
779
780 static struct dmi_system_id __initdata compal_dmi_table[] = {
781         {
782                 .ident = "FL90/IFL90",
783                 .matches = {
784                         DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
785                         DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
786                 },
787                 .callback = dmi_check_cb
788         },
789         {
790                 .ident = "FL90/IFL90",
791                 .matches = {
792                         DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
793                         DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
794                 },
795                 .callback = dmi_check_cb
796         },
797         {
798                 .ident = "FL91/IFL91",
799                 .matches = {
800                         DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
801                         DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
802                 },
803                 .callback = dmi_check_cb
804         },
805         {
806                 .ident = "FL92/JFL92",
807                 .matches = {
808                         DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
809                         DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
810                 },
811                 .callback = dmi_check_cb
812         },
813         {
814                 .ident = "FT00/IFT00",
815                 .matches = {
816                         DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
817                         DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
818                 },
819                 .callback = dmi_check_cb
820         },
821         {
822                 .ident = "Dell Mini 9",
823                 .matches = {
824                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
825                         DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
826                 },
827                 .callback = dmi_check_cb
828         },
829         {
830                 .ident = "Dell Mini 10",
831                 .matches = {
832                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
833                         DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
834                 },
835                 .callback = dmi_check_cb
836         },
837         {
838                 .ident = "Dell Mini 10v",
839                 .matches = {
840                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
841                         DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
842                 },
843                 .callback = dmi_check_cb
844         },
845         {
846                 .ident = "Dell Mini 1012",
847                 .matches = {
848                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
849                         DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
850                 },
851                 .callback = dmi_check_cb
852         },
853         {
854                 .ident = "Dell Inspiron 11z",
855                 .matches = {
856                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
857                         DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
858                 },
859                 .callback = dmi_check_cb
860         },
861         {
862                 .ident = "Dell Mini 12",
863                 .matches = {
864                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
865                         DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
866                 },
867                 .callback = dmi_check_cb
868         },
869         {
870                 .ident = "JHL90",
871                 .matches = {
872                         DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
873                         DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
874                 },
875                 .callback = dmi_check_cb_extra
876         },
877         {
878                 .ident = "KHLB2",
879                 .matches = {
880                         DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
881                         DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
882                 },
883                 .callback = dmi_check_cb_extra
884         },
885         { }
886 };
887 MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
888
889 static void initialize_power_supply_data(struct compal_data *data)
890 {
891         data->psy.name = DRIVER_NAME;
892         data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
893         data->psy.properties = compal_bat_properties;
894         data->psy.num_properties = ARRAY_SIZE(compal_bat_properties);
895         data->psy.get_property = bat_get_property;
896
897         ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
898                                         data->bat_manufacturer_name,
899                                         BAT_MANUFACTURER_NAME_LEN);
900         data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
901
902         ec_read_sequence(BAT_MODEL_NAME_ADDR,
903                                         data->bat_model_name,
904                                         BAT_MODEL_NAME_LEN);
905         data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
906
907         scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
908                                 ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
909 }
910
911 static void initialize_fan_control_data(struct compal_data *data)
912 {
913         data->pwm_enable = 2; /* Keep motherboard in control for now */
914         data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception
915                                  if we take over... */
916 }
917
918 static int setup_rfkill(void)
919 {
920         int ret;
921
922         wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
923                                 RFKILL_TYPE_WLAN, &compal_rfkill_ops,
924                                 (void *) WIRELESS_WLAN);
925         if (!wifi_rfkill)
926                 return -ENOMEM;
927
928         ret = rfkill_register(wifi_rfkill);
929         if (ret)
930                 goto err_wifi;
931
932         bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
933                                 RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
934                                 (void *) WIRELESS_BT);
935         if (!bt_rfkill) {
936                 ret = -ENOMEM;
937                 goto err_allocate_bt;
938         }
939         ret = rfkill_register(bt_rfkill);
940         if (ret)
941                 goto err_register_bt;
942
943         return 0;
944
945 err_register_bt:
946         rfkill_destroy(bt_rfkill);
947
948 err_allocate_bt:
949         rfkill_unregister(wifi_rfkill);
950
951 err_wifi:
952         rfkill_destroy(wifi_rfkill);
953
954         return ret;
955 }
956
957 static int __init compal_init(void)
958 {
959         int ret;
960
961         if (acpi_disabled) {
962                 pr_err("ACPI needs to be enabled for this driver to work!\n");
963                 return -ENODEV;
964         }
965
966         if (!force && !dmi_check_system(compal_dmi_table)) {
967                 pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
968                 return -ENODEV;
969         }
970
971         if (!acpi_video_backlight_support()) {
972                 struct backlight_properties props;
973                 memset(&props, 0, sizeof(struct backlight_properties));
974                 props.type = BACKLIGHT_PLATFORM;
975                 props.max_brightness = BACKLIGHT_LEVEL_MAX;
976                 compalbl_device = backlight_device_register(DRIVER_NAME,
977                                                             NULL, NULL,
978                                                             &compalbl_ops,
979                                                             &props);
980                 if (IS_ERR(compalbl_device))
981                         return PTR_ERR(compalbl_device);
982         }
983
984         ret = platform_driver_register(&compal_driver);
985         if (ret)
986                 goto err_backlight;
987
988         compal_device = platform_device_alloc(DRIVER_NAME, -1);
989         if (!compal_device) {
990                 ret = -ENOMEM;
991                 goto err_platform_driver;
992         }
993
994         ret = platform_device_add(compal_device); /* This calls compal_probe */
995         if (ret)
996                 goto err_platform_device;
997
998         ret = setup_rfkill();
999         if (ret)
1000                 goto err_rfkill;
1001
1002         pr_info("Driver " DRIVER_VERSION " successfully loaded\n");
1003         return 0;
1004
1005 err_rfkill:
1006         platform_device_del(compal_device);
1007
1008 err_platform_device:
1009         platform_device_put(compal_device);
1010
1011 err_platform_driver:
1012         platform_driver_unregister(&compal_driver);
1013
1014 err_backlight:
1015         backlight_device_unregister(compalbl_device);
1016
1017         return ret;
1018 }
1019
1020 static int compal_probe(struct platform_device *pdev)
1021 {
1022         int err;
1023         struct compal_data *data;
1024
1025         if (!extra_features)
1026                 return 0;
1027
1028         /* Fan control */
1029         data = kzalloc(sizeof(struct compal_data), GFP_KERNEL);
1030         if (!data)
1031                 return -ENOMEM;
1032
1033         initialize_fan_control_data(data);
1034
1035         err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
1036         if (err) {
1037                 kfree(data);
1038                 return err;
1039         }
1040
1041         data->hwmon_dev = hwmon_device_register(&pdev->dev);
1042         if (IS_ERR(data->hwmon_dev)) {
1043                 err = PTR_ERR(data->hwmon_dev);
1044                 sysfs_remove_group(&pdev->dev.kobj,
1045                                 &compal_attribute_group);
1046                 kfree(data);
1047                 return err;
1048         }
1049
1050         /* Power supply */
1051         initialize_power_supply_data(data);
1052         power_supply_register(&compal_device->dev, &data->psy);
1053
1054         platform_set_drvdata(pdev, data);
1055
1056         return 0;
1057 }
1058
1059 static void __exit compal_cleanup(void)
1060 {
1061         platform_device_unregister(compal_device);
1062         platform_driver_unregister(&compal_driver);
1063         backlight_device_unregister(compalbl_device);
1064         rfkill_unregister(wifi_rfkill);
1065         rfkill_unregister(bt_rfkill);
1066         rfkill_destroy(wifi_rfkill);
1067         rfkill_destroy(bt_rfkill);
1068
1069         pr_info("Driver unloaded\n");
1070 }
1071
1072 static int compal_remove(struct platform_device *pdev)
1073 {
1074         struct compal_data *data;
1075
1076         if (!extra_features)
1077                 return 0;
1078
1079         pr_info("Unloading: resetting fan control to motherboard\n");
1080         pwm_disable_control();
1081
1082         data = platform_get_drvdata(pdev);
1083         hwmon_device_unregister(data->hwmon_dev);
1084         power_supply_unregister(&data->psy);
1085
1086         kfree(data);
1087
1088         sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group);
1089
1090         return 0;
1091 }
1092
1093
1094 module_init(compal_init);
1095 module_exit(compal_cleanup);
1096
1097 MODULE_AUTHOR("Cezary Jackiewicz");
1098 MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
1099 MODULE_DESCRIPTION("Compal Laptop Support");
1100 MODULE_VERSION(DRIVER_VERSION);
1101 MODULE_LICENSE("GPL");