|
@@ -148,6 +148,10 @@ static int sony_nc_battery_care_setup(struct platform_device *pd,
|
|
|
unsigned int handle);
|
|
|
static void sony_nc_battery_care_cleanup(struct platform_device *pd);
|
|
|
|
|
|
+static int sony_nc_thermal_setup(struct platform_device *pd);
|
|
|
+static void sony_nc_thermal_cleanup(struct platform_device *pd);
|
|
|
+static void sony_nc_thermal_resume(void);
|
|
|
+
|
|
|
enum sony_nc_rfkill {
|
|
|
SONY_WIFI,
|
|
|
SONY_BLUETOOTH,
|
|
@@ -1282,6 +1286,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
|
|
|
pr_err("couldn't set up battery care function (%d)\n",
|
|
|
result);
|
|
|
break;
|
|
|
+ case 0x0122:
|
|
|
+ result = sony_nc_thermal_setup(pf_device);
|
|
|
+ if (result)
|
|
|
+ pr_err("couldn't set up thermal profile function (%d)\n",
|
|
|
+ result);
|
|
|
+ break;
|
|
|
case 0x0124:
|
|
|
case 0x0135:
|
|
|
sony_nc_rfkill_setup(device);
|
|
@@ -1323,6 +1333,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
|
|
|
case 0x013f:
|
|
|
sony_nc_battery_care_cleanup(pd);
|
|
|
break;
|
|
|
+ case 0x0122:
|
|
|
+ sony_nc_thermal_cleanup(pd);
|
|
|
+ break;
|
|
|
case 0x0124:
|
|
|
case 0x0135:
|
|
|
sony_nc_rfkill_cleanup();
|
|
@@ -1362,6 +1375,9 @@ static void sony_nc_function_resume(void)
|
|
|
/* re-enable hotkeys */
|
|
|
sony_call_snc_handle(handle, 0x100, &result);
|
|
|
break;
|
|
|
+ case 0x0122:
|
|
|
+ sony_nc_thermal_resume();
|
|
|
+ break;
|
|
|
case 0x0124:
|
|
|
case 0x0135:
|
|
|
sony_nc_rfkill_update();
|
|
@@ -1923,6 +1939,173 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+struct snc_thermal_ctrl {
|
|
|
+ unsigned int mode;
|
|
|
+ unsigned int profiles;
|
|
|
+ struct device_attribute mode_attr;
|
|
|
+ struct device_attribute profiles_attr;
|
|
|
+};
|
|
|
+static struct snc_thermal_ctrl *th_handle;
|
|
|
+
|
|
|
+#define THM_PROFILE_MAX 3
|
|
|
+static const char * const snc_thermal_profiles[] = {
|
|
|
+ "balanced",
|
|
|
+ "silent",
|
|
|
+ "performance"
|
|
|
+};
|
|
|
+
|
|
|
+static int sony_nc_thermal_mode_set(unsigned short mode)
|
|
|
+{
|
|
|
+ unsigned int result;
|
|
|
+
|
|
|
+ /* the thermal profile seems to be a two bit bitmask:
|
|
|
+ * lsb -> silent
|
|
|
+ * msb -> performance
|
|
|
+ * no bit set is the normal operation and is always valid
|
|
|
+ * Some vaio models only have "balanced" and "performance"
|
|
|
+ */
|
|
|
+ if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ th_handle->mode = mode;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int sony_nc_thermal_mode_get(void)
|
|
|
+{
|
|
|
+ unsigned int result;
|
|
|
+
|
|
|
+ if (sony_call_snc_handle(0x0122, 0x0100, &result))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return result & 0xff;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buffer)
|
|
|
+{
|
|
|
+ short cnt;
|
|
|
+ size_t idx = 0;
|
|
|
+
|
|
|
+ for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
|
|
|
+ if (!cnt || (th_handle->profiles & cnt))
|
|
|
+ idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
|
|
|
+ snc_thermal_profiles[cnt]);
|
|
|
+ }
|
|
|
+ idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n");
|
|
|
+
|
|
|
+ return idx;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_thermal_mode_store(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ const char *buffer, size_t count)
|
|
|
+{
|
|
|
+ unsigned short cmd;
|
|
|
+ size_t len = count;
|
|
|
+
|
|
|
+ if (count == 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* skip the newline if present */
|
|
|
+ if (buffer[len - 1] == '\n')
|
|
|
+ len--;
|
|
|
+
|
|
|
+ for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
|
|
|
+ if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (sony_nc_thermal_mode_set(cmd))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t sony_nc_thermal_mode_show(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buffer)
|
|
|
+{
|
|
|
+ ssize_t count = 0;
|
|
|
+ unsigned int mode = sony_nc_thermal_mode_get();
|
|
|
+
|
|
|
+ if (mode < 0)
|
|
|
+ return mode;
|
|
|
+
|
|
|
+ count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static int sony_nc_thermal_setup(struct platform_device *pd)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
|
|
|
+ if (!th_handle)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
|
|
|
+ if (ret) {
|
|
|
+ pr_warn("couldn't to read the thermal profiles\n");
|
|
|
+ goto outkzalloc;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = sony_nc_thermal_mode_get();
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_warn("couldn't to read the current thermal profile");
|
|
|
+ goto outkzalloc;
|
|
|
+ }
|
|
|
+ th_handle->mode = ret;
|
|
|
+
|
|
|
+ sysfs_attr_init(&th_handle->profiles_attr.attr);
|
|
|
+ th_handle->profiles_attr.attr.name = "thermal_profiles";
|
|
|
+ th_handle->profiles_attr.attr.mode = S_IRUGO;
|
|
|
+ th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
|
|
|
+
|
|
|
+ sysfs_attr_init(&th_handle->mode_attr.attr);
|
|
|
+ th_handle->mode_attr.attr.name = "thermal_control";
|
|
|
+ th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
|
|
|
+ th_handle->mode_attr.show = sony_nc_thermal_mode_show;
|
|
|
+ th_handle->mode_attr.store = sony_nc_thermal_mode_store;
|
|
|
+
|
|
|
+ ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
|
|
|
+ if (ret)
|
|
|
+ goto outkzalloc;
|
|
|
+
|
|
|
+ ret = device_create_file(&pd->dev, &th_handle->mode_attr);
|
|
|
+ if (ret)
|
|
|
+ goto outprofiles;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+outprofiles:
|
|
|
+ device_remove_file(&pd->dev, &th_handle->profiles_attr);
|
|
|
+outkzalloc:
|
|
|
+ kfree(th_handle);
|
|
|
+ th_handle = NULL;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void sony_nc_thermal_cleanup(struct platform_device *pd)
|
|
|
+{
|
|
|
+ if (th_handle) {
|
|
|
+ device_remove_file(&pd->dev, &th_handle->profiles_attr);
|
|
|
+ device_remove_file(&pd->dev, &th_handle->mode_attr);
|
|
|
+ kfree(th_handle);
|
|
|
+ th_handle = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void sony_nc_thermal_resume(void)
|
|
|
+{
|
|
|
+ unsigned int status = sony_nc_thermal_mode_get();
|
|
|
+
|
|
|
+ if (status != th_handle->mode)
|
|
|
+ sony_nc_thermal_mode_set(th_handle->mode);
|
|
|
+}
|
|
|
+
|
|
|
static void sony_nc_backlight_ng_read_limits(int handle,
|
|
|
struct sony_backlight_props *props)
|
|
|
{
|