xref: /linux/drivers/platform/x86/compal-laptop.c (revision 1e525507)
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(!backlight_is_blank(b));
328 	return 0;
329 }
330 
331 static const struct backlight_ops compalbl_ops = {
332 	.get_brightness = bl_get_brightness,
333 	.update_status	= bl_update_status,
334 };
335 
336 
337 /* Wireless interface */
338 static int compal_rfkill_set(void *data, bool blocked)
339 {
340 	unsigned long radio = (unsigned long) data;
341 	u8 result = ec_read_u8(WIRELESS_ADDR);
342 	u8 value;
343 
344 	if (!blocked)
345 		value = (u8) (result | radio);
346 	else
347 		value = (u8) (result & ~radio);
348 	ec_write(WIRELESS_ADDR, value);
349 
350 	return 0;
351 }
352 
353 static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
354 {
355 	u8 result = ec_read_u8(WIRELESS_ADDR);
356 	bool hw_blocked = !(result & WIRELESS_KILLSWITCH);
357 	rfkill_set_hw_state(rfkill, hw_blocked);
358 }
359 
360 static const struct rfkill_ops compal_rfkill_ops = {
361 	.poll = compal_rfkill_poll,
362 	.set_block = compal_rfkill_set,
363 };
364 
365 
366 /* Wake_up interface */
367 #define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK)			\
368 static ssize_t NAME##_show(struct device *dev,				\
369 	struct device_attribute *attr, char *buf)			\
370 {									\
371 	return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0));	\
372 }									\
373 static ssize_t NAME##_store(struct device *dev,				\
374 	struct device_attribute *attr, const char *buf, size_t count)	\
375 {									\
376 	int state;							\
377 	u8 old_val = ec_read_u8(ADDR);					\
378 	if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1))	\
379 		return -EINVAL;						\
380 	ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK));	\
381 	return count;							\
382 }
383 
384 SIMPLE_MASKED_STORE_SHOW(wake_up_pme,	WAKE_UP_ADDR, WAKE_UP_PME)
385 SIMPLE_MASKED_STORE_SHOW(wake_up_modem,	WAKE_UP_ADDR, WAKE_UP_MODEM)
386 SIMPLE_MASKED_STORE_SHOW(wake_up_lan,	WAKE_UP_ADDR, WAKE_UP_LAN)
387 SIMPLE_MASKED_STORE_SHOW(wake_up_wlan,	WAKE_UP_ADDR, WAKE_UP_WLAN)
388 SIMPLE_MASKED_STORE_SHOW(wake_up_key,	WAKE_UP_ADDR, WAKE_UP_KEY)
389 SIMPLE_MASKED_STORE_SHOW(wake_up_mouse,	WAKE_UP_ADDR, WAKE_UP_MOUSE)
390 
391 /* Fan control interface */
392 static ssize_t pwm_enable_show(struct device *dev,
393 		struct device_attribute *attr, char *buf)
394 {
395 	struct compal_data *data = dev_get_drvdata(dev);
396 	return sprintf(buf, "%d\n", data->pwm_enable);
397 }
398 
399 static ssize_t pwm_enable_store(struct device *dev,
400 		struct device_attribute *attr, const char *buf, size_t count)
401 {
402 	struct compal_data *data = dev_get_drvdata(dev);
403 	long val;
404 	int err;
405 
406 	err = kstrtol(buf, 10, &val);
407 	if (err)
408 		return err;
409 	if (val < 0)
410 		return -EINVAL;
411 
412 	data->pwm_enable = val;
413 
414 	switch (val) {
415 	case 0:  /* Full speed */
416 		pwm_enable_control();
417 		set_pwm(255);
418 		break;
419 	case 1:  /* As set by pwm1 */
420 		pwm_enable_control();
421 		set_pwm(data->curr_pwm);
422 		break;
423 	default: /* Control by motherboard */
424 		pwm_disable_control();
425 		break;
426 	}
427 
428 	return count;
429 }
430 
431 static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
432 		char *buf)
433 {
434 	struct compal_data *data = dev_get_drvdata(dev);
435 	return sprintf(buf, "%hhu\n", data->curr_pwm);
436 }
437 
438 static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
439 		const char *buf, size_t count)
440 {
441 	struct compal_data *data = dev_get_drvdata(dev);
442 	long val;
443 	int err;
444 
445 	err = kstrtol(buf, 10, &val);
446 	if (err)
447 		return err;
448 	if (val < 0 || val > 255)
449 		return -EINVAL;
450 
451 	data->curr_pwm = val;
452 
453 	if (data->pwm_enable != 1)
454 		return count;
455 	set_pwm(val);
456 
457 	return count;
458 }
459 
460 static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
461 		char *buf)
462 {
463 	return sprintf(buf, "%d\n", get_fan_rpm());
464 }
465 
466 
467 /* Temperature interface */
468 #define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL)	\
469 static ssize_t temp_##POSTFIX(struct device *dev,			\
470 		struct device_attribute *attr, char *buf)		\
471 {									\
472 	return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS));	\
473 }									\
474 static ssize_t label_##POSTFIX(struct device *dev,			\
475 		struct device_attribute *attr, char *buf)		\
476 {									\
477 	return sprintf(buf, "%s\n", LABEL);				\
478 }
479 
480 /* Labels as in service guide */
481 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu,        TEMP_CPU,        "CPU_TEMP");
482 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local,  TEMP_CPU_LOCAL,  "CPU_TEMP_LOCAL");
483 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS,    TEMP_CPU_DTS,    "CPU_DTS");
484 TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge");
485 TEMPERATURE_SHOW_TEMP_AND_LABEL(vga,        TEMP_VGA,        "VGA_TEMP");
486 TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN,       TEMP_SKIN,       "SKIN_TEMP90");
487 
488 
489 /* Power supply interface */
490 static int bat_status(void)
491 {
492 	u8 status0 = ec_read_u8(BAT_STATUS0);
493 	u8 status1 = ec_read_u8(BAT_STATUS1);
494 
495 	if (status0 & BAT_S0_CHARGING)
496 		return POWER_SUPPLY_STATUS_CHARGING;
497 	if (status0 & BAT_S0_DISCHARGE)
498 		return POWER_SUPPLY_STATUS_DISCHARGING;
499 	if (status1 & BAT_S1_FULL)
500 		return POWER_SUPPLY_STATUS_FULL;
501 	return POWER_SUPPLY_STATUS_NOT_CHARGING;
502 }
503 
504 static int bat_health(void)
505 {
506 	u8 status = ec_read_u8(BAT_STOP_CHARGE1);
507 
508 	if (status & BAT_STOP_CHRG1_OVERTEMPERATURE)
509 		return POWER_SUPPLY_HEALTH_OVERHEAT;
510 	if (status & BAT_STOP_CHRG1_OVERVOLTAGE)
511 		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
512 	if (status & BAT_STOP_CHRG1_BAD_CELL)
513 		return POWER_SUPPLY_HEALTH_DEAD;
514 	if (status & BAT_STOP_CHRG1_COMM_FAIL)
515 		return POWER_SUPPLY_HEALTH_UNKNOWN;
516 	return POWER_SUPPLY_HEALTH_GOOD;
517 }
518 
519 static int bat_is_present(void)
520 {
521 	u8 status = ec_read_u8(BAT_STATUS2);
522 	return ((status & BAT_S1_EXISTS) != 0);
523 }
524 
525 static int bat_technology(void)
526 {
527 	u8 status = ec_read_u8(BAT_STATUS1);
528 
529 	if (status & BAT_S1_LiION_OR_NiMH)
530 		return POWER_SUPPLY_TECHNOLOGY_LION;
531 	return POWER_SUPPLY_TECHNOLOGY_NiMH;
532 }
533 
534 static int bat_capacity_level(void)
535 {
536 	u8 status0 = ec_read_u8(BAT_STATUS0);
537 	u8 status1 = ec_read_u8(BAT_STATUS1);
538 	u8 status2 = ec_read_u8(BAT_STATUS2);
539 
540 	if (status0 & BAT_S0_DISCHRG_CRITICAL
541 			|| status1 & BAT_S1_EMPTY
542 			|| status2 & BAT_S2_LOW_LOW)
543 		return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
544 	if (status0 & BAT_S0_LOW)
545 		return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
546 	if (status1 & BAT_S1_FULL)
547 		return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
548 	return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
549 }
550 
551 static int bat_get_property(struct power_supply *psy,
552 				enum power_supply_property psp,
553 				union power_supply_propval *val)
554 {
555 	struct compal_data *data = power_supply_get_drvdata(psy);
556 
557 	switch (psp) {
558 	case POWER_SUPPLY_PROP_STATUS:
559 		val->intval = bat_status();
560 		break;
561 	case POWER_SUPPLY_PROP_HEALTH:
562 		val->intval = bat_health();
563 		break;
564 	case POWER_SUPPLY_PROP_PRESENT:
565 		val->intval = bat_is_present();
566 		break;
567 	case POWER_SUPPLY_PROP_TECHNOLOGY:
568 		val->intval = bat_technology();
569 		break;
570 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: /* THE design voltage... */
571 		val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000;
572 		break;
573 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
574 		val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000;
575 		break;
576 	case POWER_SUPPLY_PROP_CURRENT_NOW:
577 		val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000;
578 		break;
579 	case POWER_SUPPLY_PROP_CURRENT_AVG:
580 		val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000;
581 		break;
582 	case POWER_SUPPLY_PROP_POWER_NOW:
583 		val->intval = ec_read_u8(BAT_POWER) * 1000000;
584 		break;
585 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
586 		val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000;
587 		break;
588 	case POWER_SUPPLY_PROP_CHARGE_NOW:
589 		val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
590 		break;
591 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
592 		val->intval = ec_read_u8(BAT_CHARGE_LIMIT);
593 		break;
594 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
595 		val->intval = BAT_CHARGE_LIMIT_MAX;
596 		break;
597 	case POWER_SUPPLY_PROP_CAPACITY:
598 		val->intval = ec_read_u8(BAT_CAPACITY);
599 		break;
600 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
601 		val->intval = bat_capacity_level();
602 		break;
603 	/* It smees that BAT_TEMP_AVG is a (2's complement?) value showing
604 	 * the number of degrees, whereas BAT_TEMP is somewhat more
605 	 * complicated. It looks like this is a negative nember with a
606 	 * 100/256 divider and an offset of 222. Both were determined
607 	 * experimentally by comparing BAT_TEMP and BAT_TEMP_AVG. */
608 	case POWER_SUPPLY_PROP_TEMP:
609 		val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8;
610 		break;
611 	case POWER_SUPPLY_PROP_TEMP_AMBIENT: /* Ambient, Avg, ... same thing */
612 		val->intval = ec_read_s8(BAT_TEMP_AVG) * 10;
613 		break;
614 	/* Neither the model name nor manufacturer name work for me. */
615 	case POWER_SUPPLY_PROP_MODEL_NAME:
616 		val->strval = data->bat_model_name;
617 		break;
618 	case POWER_SUPPLY_PROP_MANUFACTURER:
619 		val->strval = data->bat_manufacturer_name;
620 		break;
621 	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
622 		val->strval = data->bat_serial_number;
623 		break;
624 	default:
625 		break;
626 	}
627 	return 0;
628 }
629 
630 static int bat_set_property(struct power_supply *psy,
631 				enum power_supply_property psp,
632 				const union power_supply_propval *val)
633 {
634 	int level;
635 
636 	switch (psp) {
637 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
638 		level = val->intval;
639 		if (level < 0 || level > BAT_CHARGE_LIMIT_MAX)
640 			return -EINVAL;
641 		if (ec_write(BAT_CHARGE_LIMIT, level) < 0)
642 			return -EIO;
643 		break;
644 	default:
645 		break;
646 	}
647 	return 0;
648 }
649 
650 static int bat_writeable_property(struct power_supply *psy,
651 				enum power_supply_property psp)
652 {
653 	switch (psp) {
654 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
655 		return 1;
656 	default:
657 		return 0;
658 	}
659 }
660 
661 
662 
663 
664 /* ============== */
665 /* Driver Globals */
666 /* ============== */
667 static DEVICE_ATTR_RW(wake_up_pme);
668 static DEVICE_ATTR_RW(wake_up_modem);
669 static DEVICE_ATTR_RW(wake_up_lan);
670 static DEVICE_ATTR_RW(wake_up_wlan);
671 static DEVICE_ATTR_RW(wake_up_key);
672 static DEVICE_ATTR_RW(wake_up_mouse);
673 
674 static DEVICE_ATTR(fan1_input,  S_IRUGO, fan_show,          NULL);
675 static DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu,          NULL);
676 static DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local,    NULL);
677 static DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS,      NULL);
678 static DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge,  NULL);
679 static DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga,          NULL);
680 static DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN,         NULL);
681 static DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu,         NULL);
682 static DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local,   NULL);
683 static DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS,     NULL);
684 static DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL);
685 static DEVICE_ATTR(temp5_label, S_IRUGO, label_vga,         NULL);
686 static DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN,        NULL);
687 static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store);
688 static DEVICE_ATTR(pwm1_enable,
689 		   S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store);
690 
691 static struct attribute *compal_platform_attrs[] = {
692 	&dev_attr_wake_up_pme.attr,
693 	&dev_attr_wake_up_modem.attr,
694 	&dev_attr_wake_up_lan.attr,
695 	&dev_attr_wake_up_wlan.attr,
696 	&dev_attr_wake_up_key.attr,
697 	&dev_attr_wake_up_mouse.attr,
698 	NULL
699 };
700 static const struct attribute_group compal_platform_attr_group = {
701 	.attrs = compal_platform_attrs
702 };
703 
704 static struct attribute *compal_hwmon_attrs[] = {
705 	&dev_attr_pwm1_enable.attr,
706 	&dev_attr_pwm1.attr,
707 	&dev_attr_fan1_input.attr,
708 	&dev_attr_temp1_input.attr,
709 	&dev_attr_temp2_input.attr,
710 	&dev_attr_temp3_input.attr,
711 	&dev_attr_temp4_input.attr,
712 	&dev_attr_temp5_input.attr,
713 	&dev_attr_temp6_input.attr,
714 	&dev_attr_temp1_label.attr,
715 	&dev_attr_temp2_label.attr,
716 	&dev_attr_temp3_label.attr,
717 	&dev_attr_temp4_label.attr,
718 	&dev_attr_temp5_label.attr,
719 	&dev_attr_temp6_label.attr,
720 	NULL
721 };
722 ATTRIBUTE_GROUPS(compal_hwmon);
723 
724 static enum power_supply_property compal_bat_properties[] = {
725 	POWER_SUPPLY_PROP_STATUS,
726 	POWER_SUPPLY_PROP_HEALTH,
727 	POWER_SUPPLY_PROP_PRESENT,
728 	POWER_SUPPLY_PROP_TECHNOLOGY,
729 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
730 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
731 	POWER_SUPPLY_PROP_CURRENT_NOW,
732 	POWER_SUPPLY_PROP_CURRENT_AVG,
733 	POWER_SUPPLY_PROP_POWER_NOW,
734 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
735 	POWER_SUPPLY_PROP_CHARGE_NOW,
736 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
737 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
738 	POWER_SUPPLY_PROP_CAPACITY,
739 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
740 	POWER_SUPPLY_PROP_TEMP,
741 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
742 	POWER_SUPPLY_PROP_MODEL_NAME,
743 	POWER_SUPPLY_PROP_MANUFACTURER,
744 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
745 };
746 
747 static struct backlight_device *compalbl_device;
748 
749 static struct platform_device *compal_device;
750 
751 static struct rfkill *wifi_rfkill;
752 static struct rfkill *bt_rfkill;
753 
754 
755 
756 
757 
758 /* =================================== */
759 /* Initialization & clean-up functions */
760 /* =================================== */
761 
762 static int dmi_check_cb(const struct dmi_system_id *id)
763 {
764 	pr_info("Identified laptop model '%s'\n", id->ident);
765 	extra_features = false;
766 	return 1;
767 }
768 
769 static int dmi_check_cb_extra(const struct dmi_system_id *id)
770 {
771 	pr_info("Identified laptop model '%s', enabling extra features\n",
772 		id->ident);
773 	extra_features = true;
774 	return 1;
775 }
776 
777 static const struct dmi_system_id compal_dmi_table[] __initconst = {
778 	{
779 		.ident = "FL90/IFL90",
780 		.matches = {
781 			DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
782 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
783 		},
784 		.callback = dmi_check_cb
785 	},
786 	{
787 		.ident = "FL90/IFL90",
788 		.matches = {
789 			DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
790 			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
791 		},
792 		.callback = dmi_check_cb
793 	},
794 	{
795 		.ident = "FL91/IFL91",
796 		.matches = {
797 			DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
798 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
799 		},
800 		.callback = dmi_check_cb
801 	},
802 	{
803 		.ident = "FL92/JFL92",
804 		.matches = {
805 			DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
806 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
807 		},
808 		.callback = dmi_check_cb
809 	},
810 	{
811 		.ident = "FT00/IFT00",
812 		.matches = {
813 			DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
814 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
815 		},
816 		.callback = dmi_check_cb
817 	},
818 	{
819 		.ident = "Dell Mini 9",
820 		.matches = {
821 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
822 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
823 		},
824 		.callback = dmi_check_cb
825 	},
826 	{
827 		.ident = "Dell Mini 10",
828 		.matches = {
829 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
830 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
831 		},
832 		.callback = dmi_check_cb
833 	},
834 	{
835 		.ident = "Dell Mini 10v",
836 		.matches = {
837 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
838 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
839 		},
840 		.callback = dmi_check_cb
841 	},
842 	{
843 		.ident = "Dell Mini 1012",
844 		.matches = {
845 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
846 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
847 		},
848 		.callback = dmi_check_cb
849 	},
850 	{
851 		.ident = "Dell Inspiron 11z",
852 		.matches = {
853 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
854 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
855 		},
856 		.callback = dmi_check_cb
857 	},
858 	{
859 		.ident = "Dell Mini 12",
860 		.matches = {
861 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
862 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
863 		},
864 		.callback = dmi_check_cb
865 	},
866 	{
867 		.ident = "JHL90",
868 		.matches = {
869 			DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
870 			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
871 		},
872 		.callback = dmi_check_cb_extra
873 	},
874 	{
875 		.ident = "KHLB2",
876 		.matches = {
877 			DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
878 			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
879 		},
880 		.callback = dmi_check_cb_extra
881 	},
882 	{ }
883 };
884 MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
885 
886 static const struct power_supply_desc psy_bat_desc = {
887 	.name		= DRIVER_NAME,
888 	.type		= POWER_SUPPLY_TYPE_BATTERY,
889 	.properties	= compal_bat_properties,
890 	.num_properties	= ARRAY_SIZE(compal_bat_properties),
891 	.get_property	= bat_get_property,
892 	.set_property	= bat_set_property,
893 	.property_is_writeable = bat_writeable_property,
894 };
895 
896 static void initialize_power_supply_data(struct compal_data *data)
897 {
898 	ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
899 					data->bat_manufacturer_name,
900 					BAT_MANUFACTURER_NAME_LEN);
901 	data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
902 
903 	ec_read_sequence(BAT_MODEL_NAME_ADDR,
904 					data->bat_model_name,
905 					BAT_MODEL_NAME_LEN);
906 	data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
907 
908 	scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
909 				ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
910 }
911 
912 static void initialize_fan_control_data(struct compal_data *data)
913 {
914 	data->pwm_enable = 2; /* Keep motherboard in control for now */
915 	data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception
916 				 if we take over... */
917 }
918 
919 static int setup_rfkill(void)
920 {
921 	int ret;
922 
923 	wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
924 				RFKILL_TYPE_WLAN, &compal_rfkill_ops,
925 				(void *) WIRELESS_WLAN);
926 	if (!wifi_rfkill)
927 		return -ENOMEM;
928 
929 	ret = rfkill_register(wifi_rfkill);
930 	if (ret)
931 		goto err_wifi;
932 
933 	bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
934 				RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
935 				(void *) WIRELESS_BT);
936 	if (!bt_rfkill) {
937 		ret = -ENOMEM;
938 		goto err_allocate_bt;
939 	}
940 	ret = rfkill_register(bt_rfkill);
941 	if (ret)
942 		goto err_register_bt;
943 
944 	return 0;
945 
946 err_register_bt:
947 	rfkill_destroy(bt_rfkill);
948 
949 err_allocate_bt:
950 	rfkill_unregister(wifi_rfkill);
951 
952 err_wifi:
953 	rfkill_destroy(wifi_rfkill);
954 
955 	return ret;
956 }
957 
958 static int compal_probe(struct platform_device *pdev)
959 {
960 	int err;
961 	struct compal_data *data;
962 	struct device *hwmon_dev;
963 	struct power_supply_config psy_cfg = {};
964 
965 	if (!extra_features)
966 		return 0;
967 
968 	/* Fan control */
969 	data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL);
970 	if (!data)
971 		return -ENOMEM;
972 
973 	initialize_fan_control_data(data);
974 
975 	err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group);
976 	if (err)
977 		return err;
978 
979 	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
980 							   "compal", data,
981 							   compal_hwmon_groups);
982 	if (IS_ERR(hwmon_dev)) {
983 		err = PTR_ERR(hwmon_dev);
984 		goto remove;
985 	}
986 
987 	/* Power supply */
988 	initialize_power_supply_data(data);
989 	psy_cfg.drv_data = data;
990 	data->psy = power_supply_register(&compal_device->dev, &psy_bat_desc,
991 					  &psy_cfg);
992 	if (IS_ERR(data->psy)) {
993 		err = PTR_ERR(data->psy);
994 		goto remove;
995 	}
996 
997 	platform_set_drvdata(pdev, data);
998 
999 	return 0;
1000 
1001 remove:
1002 	sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
1003 	return err;
1004 }
1005 
1006 static void compal_remove(struct platform_device *pdev)
1007 {
1008 	struct compal_data *data;
1009 
1010 	if (!extra_features)
1011 		return;
1012 
1013 	pr_info("Unloading: resetting fan control to motherboard\n");
1014 	pwm_disable_control();
1015 
1016 	data = platform_get_drvdata(pdev);
1017 	power_supply_unregister(data->psy);
1018 
1019 	sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
1020 }
1021 
1022 static struct platform_driver compal_driver = {
1023 	.driver = {
1024 		.name = DRIVER_NAME,
1025 	},
1026 	.probe	= compal_probe,
1027 	.remove_new = compal_remove,
1028 };
1029 
1030 static int __init compal_init(void)
1031 {
1032 	int ret;
1033 
1034 	if (acpi_disabled) {
1035 		pr_err("ACPI needs to be enabled for this driver to work!\n");
1036 		return -ENODEV;
1037 	}
1038 
1039 	if (!force && !dmi_check_system(compal_dmi_table)) {
1040 		pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
1041 		return -ENODEV;
1042 	}
1043 
1044 	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1045 		struct backlight_properties props;
1046 		memset(&props, 0, sizeof(struct backlight_properties));
1047 		props.type = BACKLIGHT_PLATFORM;
1048 		props.max_brightness = BACKLIGHT_LEVEL_MAX;
1049 		compalbl_device = backlight_device_register(DRIVER_NAME,
1050 							    NULL, NULL,
1051 							    &compalbl_ops,
1052 							    &props);
1053 		if (IS_ERR(compalbl_device))
1054 			return PTR_ERR(compalbl_device);
1055 	}
1056 
1057 	ret = platform_driver_register(&compal_driver);
1058 	if (ret)
1059 		goto err_backlight;
1060 
1061 	compal_device = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE);
1062 	if (!compal_device) {
1063 		ret = -ENOMEM;
1064 		goto err_platform_driver;
1065 	}
1066 
1067 	ret = platform_device_add(compal_device); /* This calls compal_probe */
1068 	if (ret)
1069 		goto err_platform_device;
1070 
1071 	ret = setup_rfkill();
1072 	if (ret)
1073 		goto err_rfkill;
1074 
1075 	pr_info("Driver " DRIVER_VERSION " successfully loaded\n");
1076 	return 0;
1077 
1078 err_rfkill:
1079 	platform_device_del(compal_device);
1080 
1081 err_platform_device:
1082 	platform_device_put(compal_device);
1083 
1084 err_platform_driver:
1085 	platform_driver_unregister(&compal_driver);
1086 
1087 err_backlight:
1088 	backlight_device_unregister(compalbl_device);
1089 
1090 	return ret;
1091 }
1092 
1093 static void __exit compal_cleanup(void)
1094 {
1095 	platform_device_unregister(compal_device);
1096 	platform_driver_unregister(&compal_driver);
1097 	backlight_device_unregister(compalbl_device);
1098 	rfkill_unregister(wifi_rfkill);
1099 	rfkill_unregister(bt_rfkill);
1100 	rfkill_destroy(wifi_rfkill);
1101 	rfkill_destroy(bt_rfkill);
1102 
1103 	pr_info("Driver unloaded\n");
1104 }
1105 
1106 module_init(compal_init);
1107 module_exit(compal_cleanup);
1108 
1109 MODULE_AUTHOR("Cezary Jackiewicz");
1110 MODULE_AUTHOR("Roald Frederickx <roald.frederickx@gmail.com>");
1111 MODULE_DESCRIPTION("Compal Laptop Support");
1112 MODULE_VERSION(DRIVER_VERSION);
1113 MODULE_LICENSE("GPL");
1114