xref: /linux/drivers/platform/x86/compal-laptop.c (revision 4359a011e259a4608afc7fb3635370c9d4ba5943)
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 int compal_probe(struct platform_device *);
725 static int compal_remove(struct platform_device *);
726 static struct platform_driver compal_driver = {
727 	.driver = {
728 		.name = DRIVER_NAME,
729 	},
730 	.probe	= compal_probe,
731 	.remove	= compal_remove,
732 };
733 
734 static enum power_supply_property compal_bat_properties[] = {
735 	POWER_SUPPLY_PROP_STATUS,
736 	POWER_SUPPLY_PROP_HEALTH,
737 	POWER_SUPPLY_PROP_PRESENT,
738 	POWER_SUPPLY_PROP_TECHNOLOGY,
739 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
740 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
741 	POWER_SUPPLY_PROP_CURRENT_NOW,
742 	POWER_SUPPLY_PROP_CURRENT_AVG,
743 	POWER_SUPPLY_PROP_POWER_NOW,
744 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
745 	POWER_SUPPLY_PROP_CHARGE_NOW,
746 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
747 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
748 	POWER_SUPPLY_PROP_CAPACITY,
749 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
750 	POWER_SUPPLY_PROP_TEMP,
751 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
752 	POWER_SUPPLY_PROP_MODEL_NAME,
753 	POWER_SUPPLY_PROP_MANUFACTURER,
754 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
755 };
756 
757 static struct backlight_device *compalbl_device;
758 
759 static struct platform_device *compal_device;
760 
761 static struct rfkill *wifi_rfkill;
762 static struct rfkill *bt_rfkill;
763 
764 
765 
766 
767 
768 /* =================================== */
769 /* Initialization & clean-up functions */
770 /* =================================== */
771 
772 static int dmi_check_cb(const struct dmi_system_id *id)
773 {
774 	pr_info("Identified laptop model '%s'\n", id->ident);
775 	extra_features = false;
776 	return 1;
777 }
778 
779 static int dmi_check_cb_extra(const struct dmi_system_id *id)
780 {
781 	pr_info("Identified laptop model '%s', enabling extra features\n",
782 		id->ident);
783 	extra_features = true;
784 	return 1;
785 }
786 
787 static const struct dmi_system_id compal_dmi_table[] __initconst = {
788 	{
789 		.ident = "FL90/IFL90",
790 		.matches = {
791 			DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
792 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
793 		},
794 		.callback = dmi_check_cb
795 	},
796 	{
797 		.ident = "FL90/IFL90",
798 		.matches = {
799 			DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
800 			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
801 		},
802 		.callback = dmi_check_cb
803 	},
804 	{
805 		.ident = "FL91/IFL91",
806 		.matches = {
807 			DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
808 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
809 		},
810 		.callback = dmi_check_cb
811 	},
812 	{
813 		.ident = "FL92/JFL92",
814 		.matches = {
815 			DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
816 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
817 		},
818 		.callback = dmi_check_cb
819 	},
820 	{
821 		.ident = "FT00/IFT00",
822 		.matches = {
823 			DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
824 			DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
825 		},
826 		.callback = dmi_check_cb
827 	},
828 	{
829 		.ident = "Dell Mini 9",
830 		.matches = {
831 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
832 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
833 		},
834 		.callback = dmi_check_cb
835 	},
836 	{
837 		.ident = "Dell Mini 10",
838 		.matches = {
839 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
840 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
841 		},
842 		.callback = dmi_check_cb
843 	},
844 	{
845 		.ident = "Dell Mini 10v",
846 		.matches = {
847 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
848 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
849 		},
850 		.callback = dmi_check_cb
851 	},
852 	{
853 		.ident = "Dell Mini 1012",
854 		.matches = {
855 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
856 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
857 		},
858 		.callback = dmi_check_cb
859 	},
860 	{
861 		.ident = "Dell Inspiron 11z",
862 		.matches = {
863 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
864 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
865 		},
866 		.callback = dmi_check_cb
867 	},
868 	{
869 		.ident = "Dell Mini 12",
870 		.matches = {
871 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
872 			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
873 		},
874 		.callback = dmi_check_cb
875 	},
876 	{
877 		.ident = "JHL90",
878 		.matches = {
879 			DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
880 			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
881 		},
882 		.callback = dmi_check_cb_extra
883 	},
884 	{
885 		.ident = "KHLB2",
886 		.matches = {
887 			DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
888 			DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
889 		},
890 		.callback = dmi_check_cb_extra
891 	},
892 	{ }
893 };
894 MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
895 
896 static const struct power_supply_desc psy_bat_desc = {
897 	.name		= DRIVER_NAME,
898 	.type		= POWER_SUPPLY_TYPE_BATTERY,
899 	.properties	= compal_bat_properties,
900 	.num_properties	= ARRAY_SIZE(compal_bat_properties),
901 	.get_property	= bat_get_property,
902 	.set_property	= bat_set_property,
903 	.property_is_writeable = bat_writeable_property,
904 };
905 
906 static void initialize_power_supply_data(struct compal_data *data)
907 {
908 	ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
909 					data->bat_manufacturer_name,
910 					BAT_MANUFACTURER_NAME_LEN);
911 	data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
912 
913 	ec_read_sequence(BAT_MODEL_NAME_ADDR,
914 					data->bat_model_name,
915 					BAT_MODEL_NAME_LEN);
916 	data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
917 
918 	scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
919 				ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
920 }
921 
922 static void initialize_fan_control_data(struct compal_data *data)
923 {
924 	data->pwm_enable = 2; /* Keep motherboard in control for now */
925 	data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception
926 				 if we take over... */
927 }
928 
929 static int setup_rfkill(void)
930 {
931 	int ret;
932 
933 	wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
934 				RFKILL_TYPE_WLAN, &compal_rfkill_ops,
935 				(void *) WIRELESS_WLAN);
936 	if (!wifi_rfkill)
937 		return -ENOMEM;
938 
939 	ret = rfkill_register(wifi_rfkill);
940 	if (ret)
941 		goto err_wifi;
942 
943 	bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
944 				RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
945 				(void *) WIRELESS_BT);
946 	if (!bt_rfkill) {
947 		ret = -ENOMEM;
948 		goto err_allocate_bt;
949 	}
950 	ret = rfkill_register(bt_rfkill);
951 	if (ret)
952 		goto err_register_bt;
953 
954 	return 0;
955 
956 err_register_bt:
957 	rfkill_destroy(bt_rfkill);
958 
959 err_allocate_bt:
960 	rfkill_unregister(wifi_rfkill);
961 
962 err_wifi:
963 	rfkill_destroy(wifi_rfkill);
964 
965 	return ret;
966 }
967 
968 static int __init compal_init(void)
969 {
970 	int ret;
971 
972 	if (acpi_disabled) {
973 		pr_err("ACPI needs to be enabled for this driver to work!\n");
974 		return -ENODEV;
975 	}
976 
977 	if (!force && !dmi_check_system(compal_dmi_table)) {
978 		pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
979 		return -ENODEV;
980 	}
981 
982 	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
983 		struct backlight_properties props;
984 		memset(&props, 0, sizeof(struct backlight_properties));
985 		props.type = BACKLIGHT_PLATFORM;
986 		props.max_brightness = BACKLIGHT_LEVEL_MAX;
987 		compalbl_device = backlight_device_register(DRIVER_NAME,
988 							    NULL, NULL,
989 							    &compalbl_ops,
990 							    &props);
991 		if (IS_ERR(compalbl_device))
992 			return PTR_ERR(compalbl_device);
993 	}
994 
995 	ret = platform_driver_register(&compal_driver);
996 	if (ret)
997 		goto err_backlight;
998 
999 	compal_device = platform_device_alloc(DRIVER_NAME, -1);
1000 	if (!compal_device) {
1001 		ret = -ENOMEM;
1002 		goto err_platform_driver;
1003 	}
1004 
1005 	ret = platform_device_add(compal_device); /* This calls compal_probe */
1006 	if (ret)
1007 		goto err_platform_device;
1008 
1009 	ret = setup_rfkill();
1010 	if (ret)
1011 		goto err_rfkill;
1012 
1013 	pr_info("Driver " DRIVER_VERSION " successfully loaded\n");
1014 	return 0;
1015 
1016 err_rfkill:
1017 	platform_device_del(compal_device);
1018 
1019 err_platform_device:
1020 	platform_device_put(compal_device);
1021 
1022 err_platform_driver:
1023 	platform_driver_unregister(&compal_driver);
1024 
1025 err_backlight:
1026 	backlight_device_unregister(compalbl_device);
1027 
1028 	return ret;
1029 }
1030 
1031 static int compal_probe(struct platform_device *pdev)
1032 {
1033 	int err;
1034 	struct compal_data *data;
1035 	struct device *hwmon_dev;
1036 	struct power_supply_config psy_cfg = {};
1037 
1038 	if (!extra_features)
1039 		return 0;
1040 
1041 	/* Fan control */
1042 	data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL);
1043 	if (!data)
1044 		return -ENOMEM;
1045 
1046 	initialize_fan_control_data(data);
1047 
1048 	err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group);
1049 	if (err)
1050 		return err;
1051 
1052 	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
1053 							   "compal", data,
1054 							   compal_hwmon_groups);
1055 	if (IS_ERR(hwmon_dev)) {
1056 		err = PTR_ERR(hwmon_dev);
1057 		goto remove;
1058 	}
1059 
1060 	/* Power supply */
1061 	initialize_power_supply_data(data);
1062 	psy_cfg.drv_data = data;
1063 	data->psy = power_supply_register(&compal_device->dev, &psy_bat_desc,
1064 					  &psy_cfg);
1065 	if (IS_ERR(data->psy)) {
1066 		err = PTR_ERR(data->psy);
1067 		goto remove;
1068 	}
1069 
1070 	platform_set_drvdata(pdev, data);
1071 
1072 	return 0;
1073 
1074 remove:
1075 	sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
1076 	return err;
1077 }
1078 
1079 static void __exit compal_cleanup(void)
1080 {
1081 	platform_device_unregister(compal_device);
1082 	platform_driver_unregister(&compal_driver);
1083 	backlight_device_unregister(compalbl_device);
1084 	rfkill_unregister(wifi_rfkill);
1085 	rfkill_unregister(bt_rfkill);
1086 	rfkill_destroy(wifi_rfkill);
1087 	rfkill_destroy(bt_rfkill);
1088 
1089 	pr_info("Driver unloaded\n");
1090 }
1091 
1092 static int compal_remove(struct platform_device *pdev)
1093 {
1094 	struct compal_data *data;
1095 
1096 	if (!extra_features)
1097 		return 0;
1098 
1099 	pr_info("Unloading: resetting fan control to motherboard\n");
1100 	pwm_disable_control();
1101 
1102 	data = platform_get_drvdata(pdev);
1103 	power_supply_unregister(data->psy);
1104 
1105 	sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
1106 
1107 	return 0;
1108 }
1109 
1110 
1111 module_init(compal_init);
1112 module_exit(compal_cleanup);
1113 
1114 MODULE_AUTHOR("Cezary Jackiewicz");
1115 MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
1116 MODULE_DESCRIPTION("Compal Laptop Support");
1117 MODULE_VERSION(DRIVER_VERSION);
1118 MODULE_LICENSE("GPL");
1119