0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0059
0060 #include <linux/module.h>
0061 #include <linux/kernel.h>
0062 #include <linux/init.h>
0063 #include <linux/acpi.h>
0064 #include <linux/dmi.h>
0065 #include <linux/backlight.h>
0066 #include <linux/platform_device.h>
0067 #include <linux/rfkill.h>
0068 #include <linux/hwmon.h>
0069 #include <linux/hwmon-sysfs.h>
0070 #include <linux/power_supply.h>
0071 #include <linux/fb.h>
0072 #include <acpi/video.h>
0073
0074
0075
0076
0077 #define DRIVER_NAME "compal-laptop"
0078 #define DRIVER_VERSION "0.2.7"
0079
0080 #define BACKLIGHT_LEVEL_ADDR 0xB9
0081 #define BACKLIGHT_LEVEL_MAX 7
0082 #define BACKLIGHT_STATE_ADDR 0x59
0083 #define BACKLIGHT_STATE_ON_DATA 0xE1
0084 #define BACKLIGHT_STATE_OFF_DATA 0xE2
0085
0086 #define WAKE_UP_ADDR 0xA4
0087 #define WAKE_UP_PME (1 << 0)
0088 #define WAKE_UP_MODEM (1 << 1)
0089 #define WAKE_UP_LAN (1 << 2)
0090 #define WAKE_UP_WLAN (1 << 4)
0091 #define WAKE_UP_KEY (1 << 6)
0092 #define WAKE_UP_MOUSE (1 << 7)
0093
0094 #define WIRELESS_ADDR 0xBB
0095 #define WIRELESS_WLAN (1 << 0)
0096 #define WIRELESS_BT (1 << 1)
0097 #define WIRELESS_WLAN_EXISTS (1 << 2)
0098 #define WIRELESS_BT_EXISTS (1 << 3)
0099 #define WIRELESS_KILLSWITCH (1 << 4)
0100
0101 #define PWM_ADDRESS 0x46
0102 #define PWM_DISABLE_ADDR 0x59
0103 #define PWM_DISABLE_DATA 0xA5
0104 #define PWM_ENABLE_ADDR 0x59
0105 #define PWM_ENABLE_DATA 0xA8
0106
0107 #define FAN_ADDRESS 0x46
0108 #define FAN_DATA 0x81
0109 #define FAN_FULL_ON_CMD 0x59
0110 #define FAN_FULL_ON_ENABLE 0x76
0111 #define FAN_FULL_ON_DISABLE 0x77
0112
0113 #define TEMP_CPU 0xB0
0114 #define TEMP_CPU_LOCAL 0xB1
0115 #define TEMP_CPU_DTS 0xB5
0116 #define TEMP_NORTHBRIDGE 0xB6
0117 #define TEMP_VGA 0xB4
0118 #define TEMP_SKIN 0xB2
0119
0120 #define BAT_MANUFACTURER_NAME_ADDR 0x10
0121 #define BAT_MANUFACTURER_NAME_LEN 9
0122 #define BAT_MODEL_NAME_ADDR 0x19
0123 #define BAT_MODEL_NAME_LEN 6
0124 #define BAT_SERIAL_NUMBER_ADDR 0xC4
0125 #define BAT_SERIAL_NUMBER_LEN 5
0126 #define BAT_CHARGE_NOW 0xC2
0127 #define BAT_CHARGE_DESIGN 0xCA
0128 #define BAT_VOLTAGE_NOW 0xC6
0129 #define BAT_VOLTAGE_DESIGN 0xC8
0130 #define BAT_CURRENT_NOW 0xD0
0131 #define BAT_CURRENT_AVG 0xD2
0132 #define BAT_POWER 0xD4
0133 #define BAT_CAPACITY 0xCE
0134 #define BAT_TEMP 0xD6
0135 #define BAT_TEMP_AVG 0xD7
0136 #define BAT_STATUS0 0xC1
0137 #define BAT_STATUS1 0xF0
0138 #define BAT_STATUS2 0xF1
0139 #define BAT_STOP_CHARGE1 0xF2
0140 #define BAT_STOP_CHARGE2 0xF3
0141 #define BAT_CHARGE_LIMIT 0x03
0142 #define BAT_CHARGE_LIMIT_MAX 100
0143
0144 #define BAT_S0_DISCHARGE (1 << 0)
0145 #define BAT_S0_DISCHRG_CRITICAL (1 << 2)
0146 #define BAT_S0_LOW (1 << 3)
0147 #define BAT_S0_CHARGING (1 << 1)
0148 #define BAT_S0_AC (1 << 7)
0149 #define BAT_S1_EXISTS (1 << 0)
0150 #define BAT_S1_FULL (1 << 1)
0151 #define BAT_S1_EMPTY (1 << 2)
0152 #define BAT_S1_LiION_OR_NiMH (1 << 7)
0153 #define BAT_S2_LOW_LOW (1 << 0)
0154 #define BAT_STOP_CHRG1_BAD_CELL (1 << 1)
0155 #define BAT_STOP_CHRG1_COMM_FAIL (1 << 2)
0156 #define BAT_STOP_CHRG1_OVERVOLTAGE (1 << 6)
0157 #define BAT_STOP_CHRG1_OVERTEMPERATURE (1 << 7)
0158
0159
0160
0161
0162
0163 struct compal_data{
0164
0165 int pwm_enable;
0166 unsigned char curr_pwm;
0167
0168
0169 struct power_supply *psy;
0170 struct power_supply_info psy_info;
0171 char bat_model_name[BAT_MODEL_NAME_LEN + 1];
0172 char bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN + 1];
0173 char bat_serial_number[BAT_SERIAL_NUMBER_LEN + 1];
0174 };
0175
0176
0177
0178
0179
0180 static bool force;
0181 module_param(force, bool, 0);
0182 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
0183
0184
0185
0186 static bool extra_features;
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 static const unsigned char pwm_lookup_table[256] = {
0201 0, 0, 0, 1, 1, 1, 2, 253, 254, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6,
0202 7, 7, 7, 8, 86, 86, 9, 9, 9, 10, 10, 10, 11, 92, 92, 12, 12, 95,
0203 13, 66, 66, 14, 14, 98, 15, 15, 15, 16, 16, 67, 17, 17, 72, 18, 70,
0204 75, 19, 90, 90, 73, 73, 73, 21, 21, 91, 91, 91, 96, 23, 94, 94, 94,
0205 94, 94, 94, 94, 94, 94, 94, 141, 141, 238, 223, 192, 139, 139, 139,
0206 139, 139, 142, 142, 142, 142, 142, 78, 78, 78, 78, 78, 76, 76, 76,
0207 76, 76, 79, 79, 79, 79, 79, 79, 79, 20, 20, 20, 20, 20, 22, 22, 22,
0208 22, 22, 24, 24, 24, 24, 24, 24, 219, 219, 219, 219, 219, 219, 219,
0209 219, 27, 27, 188, 188, 28, 28, 28, 29, 186, 186, 186, 186, 186,
0210 186, 186, 186, 186, 186, 31, 31, 31, 31, 31, 32, 32, 32, 41, 33,
0211 33, 33, 33, 33, 252, 252, 34, 34, 34, 43, 35, 35, 35, 36, 36, 38,
0212 206, 206, 206, 206, 206, 206, 206, 206, 206, 37, 37, 37, 46, 46,
0213 47, 47, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 48, 48,
0214 48, 48, 48, 40, 40, 40, 49, 42, 42, 42, 42, 42, 42, 42, 42, 44,
0215 189, 189, 189, 189, 54, 54, 45, 45, 45, 45, 45, 45, 45, 45, 251,
0216 191, 199, 199, 199, 199, 199, 215, 215, 215, 215, 187, 187, 187,
0217 187, 187, 193, 50
0218 };
0219
0220
0221
0222
0223
0224
0225
0226
0227 static u8 ec_read_u8(u8 addr)
0228 {
0229 u8 value = 0;
0230 ec_read(addr, &value);
0231 return value;
0232 }
0233
0234 static s8 ec_read_s8(u8 addr)
0235 {
0236 return (s8)ec_read_u8(addr);
0237 }
0238
0239 static u16 ec_read_u16(u8 addr)
0240 {
0241 int hi, lo;
0242 lo = ec_read_u8(addr);
0243 hi = ec_read_u8(addr + 1);
0244 return (hi << 8) + lo;
0245 }
0246
0247 static s16 ec_read_s16(u8 addr)
0248 {
0249 return (s16) ec_read_u16(addr);
0250 }
0251
0252 static void ec_read_sequence(u8 addr, u8 *buf, int len)
0253 {
0254 int i;
0255 for (i = 0; i < len; i++)
0256 ec_read(addr + i, buf + i);
0257 }
0258
0259
0260
0261 static int set_backlight_level(int level)
0262 {
0263 if (level < 0 || level > BACKLIGHT_LEVEL_MAX)
0264 return -EINVAL;
0265
0266 ec_write(BACKLIGHT_LEVEL_ADDR, level);
0267
0268 return 0;
0269 }
0270
0271 static int get_backlight_level(void)
0272 {
0273 return (int) ec_read_u8(BACKLIGHT_LEVEL_ADDR);
0274 }
0275
0276 static void set_backlight_state(bool on)
0277 {
0278 u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA;
0279 ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0);
0280 }
0281
0282
0283
0284 static void pwm_enable_control(void)
0285 {
0286 unsigned char writeData = PWM_ENABLE_DATA;
0287 ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0);
0288 }
0289
0290 static void pwm_disable_control(void)
0291 {
0292 unsigned char writeData = PWM_DISABLE_DATA;
0293 ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0);
0294 }
0295
0296 static void set_pwm(int pwm)
0297 {
0298 ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0);
0299 }
0300
0301 static int get_fan_rpm(void)
0302 {
0303 u8 value, data = FAN_DATA;
0304 ec_transaction(FAN_ADDRESS, &data, 1, &value, 1);
0305 return 100 * (int)value;
0306 }
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316 static int bl_get_brightness(struct backlight_device *b)
0317 {
0318 return get_backlight_level();
0319 }
0320
0321 static int bl_update_status(struct backlight_device *b)
0322 {
0323 int ret = set_backlight_level(b->props.brightness);
0324 if (ret)
0325 return ret;
0326
0327 set_backlight_state(!backlight_is_blank(b));
0328 return 0;
0329 }
0330
0331 static const struct backlight_ops compalbl_ops = {
0332 .get_brightness = bl_get_brightness,
0333 .update_status = bl_update_status,
0334 };
0335
0336
0337
0338 static int compal_rfkill_set(void *data, bool blocked)
0339 {
0340 unsigned long radio = (unsigned long) data;
0341 u8 result = ec_read_u8(WIRELESS_ADDR);
0342 u8 value;
0343
0344 if (!blocked)
0345 value = (u8) (result | radio);
0346 else
0347 value = (u8) (result & ~radio);
0348 ec_write(WIRELESS_ADDR, value);
0349
0350 return 0;
0351 }
0352
0353 static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
0354 {
0355 u8 result = ec_read_u8(WIRELESS_ADDR);
0356 bool hw_blocked = !(result & WIRELESS_KILLSWITCH);
0357 rfkill_set_hw_state(rfkill, hw_blocked);
0358 }
0359
0360 static const struct rfkill_ops compal_rfkill_ops = {
0361 .poll = compal_rfkill_poll,
0362 .set_block = compal_rfkill_set,
0363 };
0364
0365
0366
0367 #define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK) \
0368 static ssize_t NAME##_show(struct device *dev, \
0369 struct device_attribute *attr, char *buf) \
0370 { \
0371 return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0)); \
0372 } \
0373 static ssize_t NAME##_store(struct device *dev, \
0374 struct device_attribute *attr, const char *buf, size_t count) \
0375 { \
0376 int state; \
0377 u8 old_val = ec_read_u8(ADDR); \
0378 if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \
0379 return -EINVAL; \
0380 ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK)); \
0381 return count; \
0382 }
0383
0384 SIMPLE_MASKED_STORE_SHOW(wake_up_pme, WAKE_UP_ADDR, WAKE_UP_PME)
0385 SIMPLE_MASKED_STORE_SHOW(wake_up_modem, WAKE_UP_ADDR, WAKE_UP_MODEM)
0386 SIMPLE_MASKED_STORE_SHOW(wake_up_lan, WAKE_UP_ADDR, WAKE_UP_LAN)
0387 SIMPLE_MASKED_STORE_SHOW(wake_up_wlan, WAKE_UP_ADDR, WAKE_UP_WLAN)
0388 SIMPLE_MASKED_STORE_SHOW(wake_up_key, WAKE_UP_ADDR, WAKE_UP_KEY)
0389 SIMPLE_MASKED_STORE_SHOW(wake_up_mouse, WAKE_UP_ADDR, WAKE_UP_MOUSE)
0390
0391
0392 static ssize_t pwm_enable_show(struct device *dev,
0393 struct device_attribute *attr, char *buf)
0394 {
0395 struct compal_data *data = dev_get_drvdata(dev);
0396 return sprintf(buf, "%d\n", data->pwm_enable);
0397 }
0398
0399 static ssize_t pwm_enable_store(struct device *dev,
0400 struct device_attribute *attr, const char *buf, size_t count)
0401 {
0402 struct compal_data *data = dev_get_drvdata(dev);
0403 long val;
0404 int err;
0405
0406 err = kstrtol(buf, 10, &val);
0407 if (err)
0408 return err;
0409 if (val < 0)
0410 return -EINVAL;
0411
0412 data->pwm_enable = val;
0413
0414 switch (val) {
0415 case 0:
0416 pwm_enable_control();
0417 set_pwm(255);
0418 break;
0419 case 1:
0420 pwm_enable_control();
0421 set_pwm(data->curr_pwm);
0422 break;
0423 default:
0424 pwm_disable_control();
0425 break;
0426 }
0427
0428 return count;
0429 }
0430
0431 static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
0432 char *buf)
0433 {
0434 struct compal_data *data = dev_get_drvdata(dev);
0435 return sprintf(buf, "%hhu\n", data->curr_pwm);
0436 }
0437
0438 static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
0439 const char *buf, size_t count)
0440 {
0441 struct compal_data *data = dev_get_drvdata(dev);
0442 long val;
0443 int err;
0444
0445 err = kstrtol(buf, 10, &val);
0446 if (err)
0447 return err;
0448 if (val < 0 || val > 255)
0449 return -EINVAL;
0450
0451 data->curr_pwm = val;
0452
0453 if (data->pwm_enable != 1)
0454 return count;
0455 set_pwm(val);
0456
0457 return count;
0458 }
0459
0460 static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
0461 char *buf)
0462 {
0463 return sprintf(buf, "%d\n", get_fan_rpm());
0464 }
0465
0466
0467
0468 #define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL) \
0469 static ssize_t temp_##POSTFIX(struct device *dev, \
0470 struct device_attribute *attr, char *buf) \
0471 { \
0472 return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS)); \
0473 } \
0474 static ssize_t label_##POSTFIX(struct device *dev, \
0475 struct device_attribute *attr, char *buf) \
0476 { \
0477 return sprintf(buf, "%s\n", LABEL); \
0478 }
0479
0480
0481 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu, TEMP_CPU, "CPU_TEMP");
0482 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local, TEMP_CPU_LOCAL, "CPU_TEMP_LOCAL");
0483 TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS, TEMP_CPU_DTS, "CPU_DTS");
0484 TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge");
0485 TEMPERATURE_SHOW_TEMP_AND_LABEL(vga, TEMP_VGA, "VGA_TEMP");
0486 TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN, TEMP_SKIN, "SKIN_TEMP90");
0487
0488
0489
0490 static int bat_status(void)
0491 {
0492 u8 status0 = ec_read_u8(BAT_STATUS0);
0493 u8 status1 = ec_read_u8(BAT_STATUS1);
0494
0495 if (status0 & BAT_S0_CHARGING)
0496 return POWER_SUPPLY_STATUS_CHARGING;
0497 if (status0 & BAT_S0_DISCHARGE)
0498 return POWER_SUPPLY_STATUS_DISCHARGING;
0499 if (status1 & BAT_S1_FULL)
0500 return POWER_SUPPLY_STATUS_FULL;
0501 return POWER_SUPPLY_STATUS_NOT_CHARGING;
0502 }
0503
0504 static int bat_health(void)
0505 {
0506 u8 status = ec_read_u8(BAT_STOP_CHARGE1);
0507
0508 if (status & BAT_STOP_CHRG1_OVERTEMPERATURE)
0509 return POWER_SUPPLY_HEALTH_OVERHEAT;
0510 if (status & BAT_STOP_CHRG1_OVERVOLTAGE)
0511 return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
0512 if (status & BAT_STOP_CHRG1_BAD_CELL)
0513 return POWER_SUPPLY_HEALTH_DEAD;
0514 if (status & BAT_STOP_CHRG1_COMM_FAIL)
0515 return POWER_SUPPLY_HEALTH_UNKNOWN;
0516 return POWER_SUPPLY_HEALTH_GOOD;
0517 }
0518
0519 static int bat_is_present(void)
0520 {
0521 u8 status = ec_read_u8(BAT_STATUS2);
0522 return ((status & BAT_S1_EXISTS) != 0);
0523 }
0524
0525 static int bat_technology(void)
0526 {
0527 u8 status = ec_read_u8(BAT_STATUS1);
0528
0529 if (status & BAT_S1_LiION_OR_NiMH)
0530 return POWER_SUPPLY_TECHNOLOGY_LION;
0531 return POWER_SUPPLY_TECHNOLOGY_NiMH;
0532 }
0533
0534 static int bat_capacity_level(void)
0535 {
0536 u8 status0 = ec_read_u8(BAT_STATUS0);
0537 u8 status1 = ec_read_u8(BAT_STATUS1);
0538 u8 status2 = ec_read_u8(BAT_STATUS2);
0539
0540 if (status0 & BAT_S0_DISCHRG_CRITICAL
0541 || status1 & BAT_S1_EMPTY
0542 || status2 & BAT_S2_LOW_LOW)
0543 return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
0544 if (status0 & BAT_S0_LOW)
0545 return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
0546 if (status1 & BAT_S1_FULL)
0547 return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
0548 return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
0549 }
0550
0551 static int bat_get_property(struct power_supply *psy,
0552 enum power_supply_property psp,
0553 union power_supply_propval *val)
0554 {
0555 struct compal_data *data = power_supply_get_drvdata(psy);
0556
0557 switch (psp) {
0558 case POWER_SUPPLY_PROP_STATUS:
0559 val->intval = bat_status();
0560 break;
0561 case POWER_SUPPLY_PROP_HEALTH:
0562 val->intval = bat_health();
0563 break;
0564 case POWER_SUPPLY_PROP_PRESENT:
0565 val->intval = bat_is_present();
0566 break;
0567 case POWER_SUPPLY_PROP_TECHNOLOGY:
0568 val->intval = bat_technology();
0569 break;
0570 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0571 val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000;
0572 break;
0573 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0574 val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000;
0575 break;
0576 case POWER_SUPPLY_PROP_CURRENT_NOW:
0577 val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000;
0578 break;
0579 case POWER_SUPPLY_PROP_CURRENT_AVG:
0580 val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000;
0581 break;
0582 case POWER_SUPPLY_PROP_POWER_NOW:
0583 val->intval = ec_read_u8(BAT_POWER) * 1000000;
0584 break;
0585 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
0586 val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000;
0587 break;
0588 case POWER_SUPPLY_PROP_CHARGE_NOW:
0589 val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
0590 break;
0591 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0592 val->intval = ec_read_u8(BAT_CHARGE_LIMIT);
0593 break;
0594 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
0595 val->intval = BAT_CHARGE_LIMIT_MAX;
0596 break;
0597 case POWER_SUPPLY_PROP_CAPACITY:
0598 val->intval = ec_read_u8(BAT_CAPACITY);
0599 break;
0600 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
0601 val->intval = bat_capacity_level();
0602 break;
0603
0604
0605
0606
0607
0608 case POWER_SUPPLY_PROP_TEMP:
0609 val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8;
0610 break;
0611 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
0612 val->intval = ec_read_s8(BAT_TEMP_AVG) * 10;
0613 break;
0614
0615 case POWER_SUPPLY_PROP_MODEL_NAME:
0616 val->strval = data->bat_model_name;
0617 break;
0618 case POWER_SUPPLY_PROP_MANUFACTURER:
0619 val->strval = data->bat_manufacturer_name;
0620 break;
0621 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
0622 val->strval = data->bat_serial_number;
0623 break;
0624 default:
0625 break;
0626 }
0627 return 0;
0628 }
0629
0630 static int bat_set_property(struct power_supply *psy,
0631 enum power_supply_property psp,
0632 const union power_supply_propval *val)
0633 {
0634 int level;
0635
0636 switch (psp) {
0637 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0638 level = val->intval;
0639 if (level < 0 || level > BAT_CHARGE_LIMIT_MAX)
0640 return -EINVAL;
0641 if (ec_write(BAT_CHARGE_LIMIT, level) < 0)
0642 return -EIO;
0643 break;
0644 default:
0645 break;
0646 }
0647 return 0;
0648 }
0649
0650 static int bat_writeable_property(struct power_supply *psy,
0651 enum power_supply_property psp)
0652 {
0653 switch (psp) {
0654 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
0655 return 1;
0656 default:
0657 return 0;
0658 }
0659 }
0660
0661
0662
0663
0664
0665
0666
0667 static DEVICE_ATTR_RW(wake_up_pme);
0668 static DEVICE_ATTR_RW(wake_up_modem);
0669 static DEVICE_ATTR_RW(wake_up_lan);
0670 static DEVICE_ATTR_RW(wake_up_wlan);
0671 static DEVICE_ATTR_RW(wake_up_key);
0672 static DEVICE_ATTR_RW(wake_up_mouse);
0673
0674 static DEVICE_ATTR(fan1_input, S_IRUGO, fan_show, NULL);
0675 static DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu, NULL);
0676 static DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local, NULL);
0677 static DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS, NULL);
0678 static DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge, NULL);
0679 static DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga, NULL);
0680 static DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN, NULL);
0681 static DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu, NULL);
0682 static DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local, NULL);
0683 static DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS, NULL);
0684 static DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL);
0685 static DEVICE_ATTR(temp5_label, S_IRUGO, label_vga, NULL);
0686 static DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN, NULL);
0687 static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store);
0688 static DEVICE_ATTR(pwm1_enable,
0689 S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store);
0690
0691 static struct attribute *compal_platform_attrs[] = {
0692 &dev_attr_wake_up_pme.attr,
0693 &dev_attr_wake_up_modem.attr,
0694 &dev_attr_wake_up_lan.attr,
0695 &dev_attr_wake_up_wlan.attr,
0696 &dev_attr_wake_up_key.attr,
0697 &dev_attr_wake_up_mouse.attr,
0698 NULL
0699 };
0700 static const struct attribute_group compal_platform_attr_group = {
0701 .attrs = compal_platform_attrs
0702 };
0703
0704 static struct attribute *compal_hwmon_attrs[] = {
0705 &dev_attr_pwm1_enable.attr,
0706 &dev_attr_pwm1.attr,
0707 &dev_attr_fan1_input.attr,
0708 &dev_attr_temp1_input.attr,
0709 &dev_attr_temp2_input.attr,
0710 &dev_attr_temp3_input.attr,
0711 &dev_attr_temp4_input.attr,
0712 &dev_attr_temp5_input.attr,
0713 &dev_attr_temp6_input.attr,
0714 &dev_attr_temp1_label.attr,
0715 &dev_attr_temp2_label.attr,
0716 &dev_attr_temp3_label.attr,
0717 &dev_attr_temp4_label.attr,
0718 &dev_attr_temp5_label.attr,
0719 &dev_attr_temp6_label.attr,
0720 NULL
0721 };
0722 ATTRIBUTE_GROUPS(compal_hwmon);
0723
0724 static int compal_probe(struct platform_device *);
0725 static int compal_remove(struct platform_device *);
0726 static struct platform_driver compal_driver = {
0727 .driver = {
0728 .name = DRIVER_NAME,
0729 },
0730 .probe = compal_probe,
0731 .remove = compal_remove,
0732 };
0733
0734 static enum power_supply_property compal_bat_properties[] = {
0735 POWER_SUPPLY_PROP_STATUS,
0736 POWER_SUPPLY_PROP_HEALTH,
0737 POWER_SUPPLY_PROP_PRESENT,
0738 POWER_SUPPLY_PROP_TECHNOLOGY,
0739 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0740 POWER_SUPPLY_PROP_VOLTAGE_NOW,
0741 POWER_SUPPLY_PROP_CURRENT_NOW,
0742 POWER_SUPPLY_PROP_CURRENT_AVG,
0743 POWER_SUPPLY_PROP_POWER_NOW,
0744 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
0745 POWER_SUPPLY_PROP_CHARGE_NOW,
0746 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
0747 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
0748 POWER_SUPPLY_PROP_CAPACITY,
0749 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
0750 POWER_SUPPLY_PROP_TEMP,
0751 POWER_SUPPLY_PROP_TEMP_AMBIENT,
0752 POWER_SUPPLY_PROP_MODEL_NAME,
0753 POWER_SUPPLY_PROP_MANUFACTURER,
0754 POWER_SUPPLY_PROP_SERIAL_NUMBER,
0755 };
0756
0757 static struct backlight_device *compalbl_device;
0758
0759 static struct platform_device *compal_device;
0760
0761 static struct rfkill *wifi_rfkill;
0762 static struct rfkill *bt_rfkill;
0763
0764
0765
0766
0767
0768
0769
0770
0771
0772 static int dmi_check_cb(const struct dmi_system_id *id)
0773 {
0774 pr_info("Identified laptop model '%s'\n", id->ident);
0775 extra_features = false;
0776 return 1;
0777 }
0778
0779 static int dmi_check_cb_extra(const struct dmi_system_id *id)
0780 {
0781 pr_info("Identified laptop model '%s', enabling extra features\n",
0782 id->ident);
0783 extra_features = true;
0784 return 1;
0785 }
0786
0787 static const struct dmi_system_id compal_dmi_table[] __initconst = {
0788 {
0789 .ident = "FL90/IFL90",
0790 .matches = {
0791 DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
0792 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
0793 },
0794 .callback = dmi_check_cb
0795 },
0796 {
0797 .ident = "FL90/IFL90",
0798 .matches = {
0799 DMI_MATCH(DMI_BOARD_NAME, "IFL90"),
0800 DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
0801 },
0802 .callback = dmi_check_cb
0803 },
0804 {
0805 .ident = "FL91/IFL91",
0806 .matches = {
0807 DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
0808 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
0809 },
0810 .callback = dmi_check_cb
0811 },
0812 {
0813 .ident = "FL92/JFL92",
0814 .matches = {
0815 DMI_MATCH(DMI_BOARD_NAME, "JFL92"),
0816 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
0817 },
0818 .callback = dmi_check_cb
0819 },
0820 {
0821 .ident = "FT00/IFT00",
0822 .matches = {
0823 DMI_MATCH(DMI_BOARD_NAME, "IFT00"),
0824 DMI_MATCH(DMI_BOARD_VERSION, "IFT00"),
0825 },
0826 .callback = dmi_check_cb
0827 },
0828 {
0829 .ident = "Dell Mini 9",
0830 .matches = {
0831 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0832 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
0833 },
0834 .callback = dmi_check_cb
0835 },
0836 {
0837 .ident = "Dell Mini 10",
0838 .matches = {
0839 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0840 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
0841 },
0842 .callback = dmi_check_cb
0843 },
0844 {
0845 .ident = "Dell Mini 10v",
0846 .matches = {
0847 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0848 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
0849 },
0850 .callback = dmi_check_cb
0851 },
0852 {
0853 .ident = "Dell Mini 1012",
0854 .matches = {
0855 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0856 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
0857 },
0858 .callback = dmi_check_cb
0859 },
0860 {
0861 .ident = "Dell Inspiron 11z",
0862 .matches = {
0863 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0864 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
0865 },
0866 .callback = dmi_check_cb
0867 },
0868 {
0869 .ident = "Dell Mini 12",
0870 .matches = {
0871 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0872 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
0873 },
0874 .callback = dmi_check_cb
0875 },
0876 {
0877 .ident = "JHL90",
0878 .matches = {
0879 DMI_MATCH(DMI_BOARD_NAME, "JHL90"),
0880 DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
0881 },
0882 .callback = dmi_check_cb_extra
0883 },
0884 {
0885 .ident = "KHLB2",
0886 .matches = {
0887 DMI_MATCH(DMI_BOARD_NAME, "KHLB2"),
0888 DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"),
0889 },
0890 .callback = dmi_check_cb_extra
0891 },
0892 { }
0893 };
0894 MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
0895
0896 static const struct power_supply_desc psy_bat_desc = {
0897 .name = DRIVER_NAME,
0898 .type = POWER_SUPPLY_TYPE_BATTERY,
0899 .properties = compal_bat_properties,
0900 .num_properties = ARRAY_SIZE(compal_bat_properties),
0901 .get_property = bat_get_property,
0902 .set_property = bat_set_property,
0903 .property_is_writeable = bat_writeable_property,
0904 };
0905
0906 static void initialize_power_supply_data(struct compal_data *data)
0907 {
0908 ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
0909 data->bat_manufacturer_name,
0910 BAT_MANUFACTURER_NAME_LEN);
0911 data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0;
0912
0913 ec_read_sequence(BAT_MODEL_NAME_ADDR,
0914 data->bat_model_name,
0915 BAT_MODEL_NAME_LEN);
0916 data->bat_model_name[BAT_MODEL_NAME_LEN] = 0;
0917
0918 scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d",
0919 ec_read_u16(BAT_SERIAL_NUMBER_ADDR));
0920 }
0921
0922 static void initialize_fan_control_data(struct compal_data *data)
0923 {
0924 data->pwm_enable = 2;
0925 data->curr_pwm = 255;
0926
0927 }
0928
0929 static int setup_rfkill(void)
0930 {
0931 int ret;
0932
0933 wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
0934 RFKILL_TYPE_WLAN, &compal_rfkill_ops,
0935 (void *) WIRELESS_WLAN);
0936 if (!wifi_rfkill)
0937 return -ENOMEM;
0938
0939 ret = rfkill_register(wifi_rfkill);
0940 if (ret)
0941 goto err_wifi;
0942
0943 bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
0944 RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
0945 (void *) WIRELESS_BT);
0946 if (!bt_rfkill) {
0947 ret = -ENOMEM;
0948 goto err_allocate_bt;
0949 }
0950 ret = rfkill_register(bt_rfkill);
0951 if (ret)
0952 goto err_register_bt;
0953
0954 return 0;
0955
0956 err_register_bt:
0957 rfkill_destroy(bt_rfkill);
0958
0959 err_allocate_bt:
0960 rfkill_unregister(wifi_rfkill);
0961
0962 err_wifi:
0963 rfkill_destroy(wifi_rfkill);
0964
0965 return ret;
0966 }
0967
0968 static int __init compal_init(void)
0969 {
0970 int ret;
0971
0972 if (acpi_disabled) {
0973 pr_err("ACPI needs to be enabled for this driver to work!\n");
0974 return -ENODEV;
0975 }
0976
0977 if (!force && !dmi_check_system(compal_dmi_table)) {
0978 pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
0979 return -ENODEV;
0980 }
0981
0982 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
0983 struct backlight_properties props;
0984 memset(&props, 0, sizeof(struct backlight_properties));
0985 props.type = BACKLIGHT_PLATFORM;
0986 props.max_brightness = BACKLIGHT_LEVEL_MAX;
0987 compalbl_device = backlight_device_register(DRIVER_NAME,
0988 NULL, NULL,
0989 &compalbl_ops,
0990 &props);
0991 if (IS_ERR(compalbl_device))
0992 return PTR_ERR(compalbl_device);
0993 }
0994
0995 ret = platform_driver_register(&compal_driver);
0996 if (ret)
0997 goto err_backlight;
0998
0999 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);
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
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
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");