diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-ideapad-laptop | 11 | ||||
-rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 43 |
2 files changed, 51 insertions, 3 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-ideapad-laptop b/Documentation/ABI/testing/sysfs-platform-ideapad-laptop index 814b01354c41..b31e782bd985 100644 --- a/Documentation/ABI/testing/sysfs-platform-ideapad-laptop +++ b/Documentation/ABI/testing/sysfs-platform-ideapad-laptop | |||
@@ -5,4 +5,15 @@ Contact: "Ike Panhc <ike.pan@canonical.com>" | |||
5 | Description: | 5 | Description: |
6 | Control the power of camera module. 1 means on, 0 means off. | 6 | Control the power of camera module. 1 means on, 0 means off. |
7 | 7 | ||
8 | What: /sys/devices/platform/ideapad/fan_mode | ||
9 | Date: June 2012 | ||
10 | KernelVersion: 3.6 | ||
11 | Contact: "Maxim Mikityanskiy <maxtram95@gmail.com>" | ||
12 | Description: | ||
13 | Change fan mode | ||
14 | There are four available modes: | ||
15 | * 0 -> Super Silent Mode | ||
16 | * 1 -> Standard Mode | ||
17 | * 2 -> Dust Cleaning | ||
18 | * 4 -> Efficient Thermal Dissipation Mode | ||
8 | 19 | ||
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 7bc1b6c60e56..dae7abe1d711 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
@@ -64,8 +64,10 @@ enum { | |||
64 | VPCCMD_R_3G, | 64 | VPCCMD_R_3G, |
65 | VPCCMD_W_3G, | 65 | VPCCMD_W_3G, |
66 | VPCCMD_R_ODD, /* 0x21 */ | 66 | VPCCMD_R_ODD, /* 0x21 */ |
67 | VPCCMD_R_RF = 0x23, | 67 | VPCCMD_W_FAN, |
68 | VPCCMD_R_RF, | ||
68 | VPCCMD_W_RF, | 69 | VPCCMD_W_RF, |
70 | VPCCMD_R_FAN = 0x2B, | ||
69 | VPCCMD_R_SPECIAL_BUTTONS = 0x31, | 71 | VPCCMD_R_SPECIAL_BUTTONS = 0x31, |
70 | VPCCMD_W_BL_POWER = 0x33, | 72 | VPCCMD_W_BL_POWER = 0x33, |
71 | }; | 73 | }; |
@@ -358,14 +360,46 @@ static ssize_t store_ideapad_cam(struct device *dev, | |||
358 | return -EINVAL; | 360 | return -EINVAL; |
359 | ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state); | 361 | ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state); |
360 | if (ret < 0) | 362 | if (ret < 0) |
361 | return ret; | 363 | return -EIO; |
362 | return count; | 364 | return count; |
363 | } | 365 | } |
364 | 366 | ||
365 | static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); | 367 | static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); |
366 | 368 | ||
369 | static ssize_t show_ideapad_fan(struct device *dev, | ||
370 | struct device_attribute *attr, | ||
371 | char *buf) | ||
372 | { | ||
373 | unsigned long result; | ||
374 | |||
375 | if (read_ec_data(ideapad_handle, VPCCMD_R_FAN, &result)) | ||
376 | return sprintf(buf, "-1\n"); | ||
377 | return sprintf(buf, "%lu\n", result); | ||
378 | } | ||
379 | |||
380 | static ssize_t store_ideapad_fan(struct device *dev, | ||
381 | struct device_attribute *attr, | ||
382 | const char *buf, size_t count) | ||
383 | { | ||
384 | int ret, state; | ||
385 | |||
386 | if (!count) | ||
387 | return 0; | ||
388 | if (sscanf(buf, "%i", &state) != 1) | ||
389 | return -EINVAL; | ||
390 | if (state < 0 || state > 4 || state == 3) | ||
391 | return -EINVAL; | ||
392 | ret = write_ec_cmd(ideapad_handle, VPCCMD_W_FAN, state); | ||
393 | if (ret < 0) | ||
394 | return -EIO; | ||
395 | return count; | ||
396 | } | ||
397 | |||
398 | static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan); | ||
399 | |||
367 | static struct attribute *ideapad_attributes[] = { | 400 | static struct attribute *ideapad_attributes[] = { |
368 | &dev_attr_camera_power.attr, | 401 | &dev_attr_camera_power.attr, |
402 | &dev_attr_fan_mode.attr, | ||
369 | NULL | 403 | NULL |
370 | }; | 404 | }; |
371 | 405 | ||
@@ -379,7 +413,10 @@ static umode_t ideapad_is_visible(struct kobject *kobj, | |||
379 | 413 | ||
380 | if (attr == &dev_attr_camera_power.attr) | 414 | if (attr == &dev_attr_camera_power.attr) |
381 | supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); | 415 | supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); |
382 | else | 416 | else if (attr == &dev_attr_fan_mode.attr) { |
417 | unsigned long value; | ||
418 | supported = !read_ec_data(ideapad_handle, VPCCMD_R_FAN, &value); | ||
419 | } else | ||
383 | supported = true; | 420 | supported = true; |
384 | 421 | ||
385 | return supported ? attr->mode : 0; | 422 | return supported ? attr->mode : 0; |