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