public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Cristiano Prisciandaro <cristiano.p@solnet.ch>
To: Dave Jones <davej@redhat.com>
Cc: cpufreq@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver
Date: Sun, 23 Nov 2008 16:27:06 +0100	[thread overview]
Message-ID: <1227454026.7262.59.camel@localhost> (raw)

From: Cristiano Prisciandaro <cristiano.p@solnet.ch>

The bios of the eeepc 900 exposes an acpi method that allows clocking
the cpu to 630/900 MHz. This driver allows controlling the frequency
switch through the cpufreq subsystem.

Signed-off-by: Cristiano Prisciandaro <cristiano.p@solnet.ch>

---

diff -uprN -X linux-2.6.vanilla/Documentation/dontdiff linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/eee900freq.c linux-2.6/arch/x86/kernel/cpu/cpufreq/eee900freq.c
--- linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/eee900freq.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/arch/x86/kernel/cpu/cpufreq/eee900freq.c	2008-11-23 15:06:56.000000000 +0100
@@ -0,0 +1,232 @@
+/*
+ * Experimental cpu frequency scaling driver for the eeepc 900
+ *
+ * Copyright (C) 2008  Cristiano Prisciandaro <cristiano.p@solnet.ch>
+ *
+ * This driver is based on the (experimental) finding that the
+ * eeepc bios exposes a method to underclock the bus/cpu.
+ *
+ * It seems to work fine with the following BIOS versions:
+ * 0501, 0601, 0704 and 0802.
+ *
+ * Parts of this code are from
+ *  asus_acpi.c Copyright (C) Julien Lerouge, Karol Kozimor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * BIG FAT DISCLAIMER: experimental code. Possibly *dangerous*
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/cpufreq.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+
+#define MNAME                    "eee900freq:"
+#define ASUS_HOTK_PREFIX         "\\_SB.ATKD"
+#define ASUS_CPUFV_READ_METHOD   "CFVG"
+#define ASUS_CPUFV_WRITE_METHOD  "CFVS"
+
+static acpi_handle handle;
+static unsigned int cpufreq_eee900_get(unsigned int cpu);
+
+/* available frequencies */
+static struct cpufreq_frequency_table eee900freq_table[] = {
+	{0, 630000},
+	{1, 900000},
+	{0, CPUFREQ_TABLE_END}
+};
+
+struct eee900_acpi_value {
+	int frequency;
+	int value;
+};
+
+static struct eee900_acpi_value eee900_acpi_values_table[] = {
+	{630000, 1},
+	{900000, 0}
+};
+
+/* read from the acpi handle (from asus_acpi.c) */
+static int read_eee900_acpi_int(acpi_handle handle, const char *method,
+				int *val)
+{
+	struct acpi_buffer output;
+	union acpi_object out_obj;
+	acpi_status status;
+
+	output.length = sizeof(out_obj);
+	output.pointer = &out_obj;
+	status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
+	*val = out_obj.integer.value;
+	return status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+}
+
+/* write to the acpi handle (from asus_acpi.c) */
+static int write_eee900_acpi_int(acpi_handle handle, const char *method,
+				 int val, struct acpi_buffer *output)
+{
+	struct acpi_object_list params;
+	union acpi_object in_obj;
+	acpi_status status;
+
+	params.count = 1;
+	params.pointer = &in_obj;
+	in_obj.type = ACPI_TYPE_INTEGER;
+	in_obj.integer.value = val;
+	status = acpi_evaluate_object(handle, (char *)method, &params, output);
+	return status == AE_OK;
+}
+
+/* return the current frequency as in acpi */
+static unsigned int cpufreq_eee900_get(unsigned int cpu)
+{
+	int value;
+
+	if (!read_eee900_acpi_int(handle, ASUS_CPUFV_READ_METHOD, &value)) {
+		printk(KERN_WARNING MNAME
+		       "unable to read current frequency from "
+		       ASUS_CPUFV_READ_METHOD "\n");
+		return -EINVAL;
+	}
+
+	switch (value) {
+	case 0x200:
+		return 900000;
+	case 0x201:
+		return 630000;
+	}
+
+	return 0;
+}
+
+static void cpufreq_eee900_set_freq(unsigned int index)
+{
+	struct cpufreq_freqs freqs;
+
+	freqs.old = cpufreq_eee900_get(0);
+	freqs.new = eee900freq_table[index].frequency;
+	freqs.cpu = 0;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	if (!write_eee900_acpi_int(handle, ASUS_CPUFV_WRITE_METHOD,
+				   eee900_acpi_values_table[index].value, NULL))
+		printk(KERN_WARNING "unable to set new frequency: val=%x",
+		       eee900_acpi_values_table[index].value);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return;
+}
+
+static int cpufreq_eee900_target(struct cpufreq_policy *policy,
+				 unsigned int target_freq,
+				 unsigned int relation)
+{
+	unsigned int newstate = 0;
+
+	if (cpufreq_frequency_table_target
+	    (policy, &eee900freq_table[0], target_freq, relation, &newstate))
+		return -EINVAL;
+
+	cpufreq_eee900_set_freq(newstate);
+
+	return 0;
+}
+
+static int cpufreq_eee900_cpu_init(struct cpufreq_policy *policy)
+{
+
+	unsigned int cfreq;
+
+	cfreq = cpufreq_eee900_get(policy->cpu);
+
+	cpufreq_frequency_table_get_attr(eee900freq_table, policy->cpu);
+
+	/* cpuinfo and default policy values */
+	policy->cpuinfo.transition_latency = 1000000;	/* assumed */
+	policy->cur = cfreq;
+
+	return cpufreq_frequency_table_cpuinfo(policy, &eee900freq_table[0]);
+}
+
+static int cpufreq_eee900_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static int cpufreq_eee900_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &eee900freq_table[0]);
+}
+
+static struct freq_attr *eee900freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver eee900freq_driver = {
+	.verify	= cpufreq_eee900_verify,
+	.target	= cpufreq_eee900_target,
+	.init	= cpufreq_eee900_cpu_init,
+	.exit	= cpufreq_eee900_cpu_exit,
+	.get	= cpufreq_eee900_get,
+	.name	= "eee900freq",
+	.owner	= THIS_MODULE,
+	.attr	= eee900freq_attr,
+};
+
+static int __init cpufreq_eee900_init(void)
+{
+	struct cpuinfo_x86 *c = &cpu_data(0);
+	acpi_status status;
+	int ret;
+	int test;
+
+	if (c->x86_vendor != X86_VENDOR_INTEL)
+		return -ENODEV;
+
+	status = acpi_get_handle(NULL, ASUS_HOTK_PREFIX, &handle);
+
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_INFO MNAME "unable to get acpi handle.\n");
+		handle = NULL;
+		return -ENODEV;
+	}
+
+	/* check if the control method is supported */
+	if (!read_eee900_acpi_int(handle, ASUS_CPUFV_READ_METHOD, &test)) {
+		printk(KERN_INFO "Get control method test failed\n");
+		return -ENODEV;
+	}
+
+	ret = cpufreq_register_driver(&eee900freq_driver);
+
+	if (!ret)
+		printk(KERN_INFO MNAME
+		       "CPU frequency scaling driver for the eeepc 900.\n");
+
+	return ret;
+}
+
+static void __exit cpufreq_eee900_exit(void)
+{
+	cpufreq_unregister_driver(&eee900freq_driver);
+	printk(KERN_INFO MNAME
+	       "CPU frequency scaling driver for the eeepc 900 unregistered.\n");
+}
+
+module_init(cpufreq_eee900_init);
+module_exit(cpufreq_eee900_exit);
+
+MODULE_AUTHOR("Cristiano Prisciandaro <cristiano.p@solnet.ch>");
+MODULE_DESCRIPTION("Frequency scaling driver for the eeepc 900.");
+MODULE_LICENSE("GPL");
diff -uprN -X linux-2.6.vanilla/Documentation/dontdiff linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Kconfig linux-2.6/arch/x86/kernel/cpu/cpufreq/Kconfig
--- linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Kconfig	2008-11-21 00:19:22.000000000 +0100
+++ linux-2.6/arch/x86/kernel/cpu/cpufreq/Kconfig	2008-11-23 12:24:47.000000000 +0100
@@ -243,6 +243,15 @@ config X86_E_POWERSAVER
 
 	  If in doubt, say N.
 
+config X86_CPUFREQ_EEEPC900
+	tristate "Eeepc 900 ACPI frequency scaling driver"
+	select CPU_FREQ_TABLE
+	depends on ACPI && X86_32 && EXPERIMENTAL
+	help
+	  This adds the CPUFreq driver for the eeepc 900.
+
+	  If in doubt, say N.
+
 comment "shared options"
 
 config X86_ACPI_CPUFREQ_PROC_INTF
diff -uprN -X linux-2.6.vanilla/Documentation/dontdiff linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Makefile linux-2.6/arch/x86/kernel/cpu/cpufreq/Makefile
--- linux-2.6.vanilla/arch/x86/kernel/cpu/cpufreq/Makefile	2008-11-21 00:19:22.000000000 +0100
+++ linux-2.6/arch/x86/kernel/cpu/cpufreq/Makefile	2008-11-23 12:24:53.000000000 +0100
@@ -14,3 +14,4 @@ obj-$(CONFIG_X86_ACPI_CPUFREQ)		+= acpi-
 obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO)	+= speedstep-centrino.o
 obj-$(CONFIG_X86_P4_CLOCKMOD)		+= p4-clockmod.o
 obj-$(CONFIG_X86_CPUFREQ_NFORCE2)	+= cpufreq-nforce2.o
+obj-$(CONFIG_X86_CPUFREQ_EEEPC900)	+= eee900freq.o




             reply	other threads:[~2008-11-23 15:38 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-23 15:27 Cristiano Prisciandaro [this message]
2008-11-23 18:04 ` [PATCH 1/1] cpufreq: eeepc 900 frequency scaling driver Pavel Machek
2008-12-02 16:15   ` Matthew Garrett
2008-12-02 20:14     ` Pavel Machek
2009-03-16  4:24       ` Len Brown
2009-03-16  8:29         ` Pavel Machek
2009-03-17  8:30           ` Fabio Comolli
2009-03-17  8:59             ` Fabio Comolli
2008-11-24  9:38 ` Tom Hughes
2008-11-24 15:13   ` Thomas Renninger
2008-11-24 16:36     ` Thomas Renninger
2008-11-24 16:41       ` [Acpi4asus-user] " Corentin Chary
2008-11-24 16:48         ` Tom Hughes
2008-11-24 16:58           ` Corentin Chary
2008-11-24 17:07             ` Tom Hughes
2008-11-24 16:46       ` Tom Hughes
2008-11-24 23:02       ` Cristiano Prisciandaro
2009-04-05  7:43         ` [Acpi4asus-user] " Corentin Chary
2009-04-05 10:20           ` Matthew Garrett
2009-04-05 11:39             ` Grigori Goronzy
2008-11-24 16:39     ` Tom Hughes
2008-11-24 19:09   ` Cristiano Prisciandaro
2008-12-03 19:26   ` Tom Hughes
2008-12-04  1:57     ` Thomas Renninger
2008-12-05 23:05       ` Tom Hughes
2008-12-06 16:35         ` Matthew Garrett
2008-12-07 15:55           ` Tom Hughes
2008-12-09 12:36             ` Pavel Machek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1227454026.7262.59.camel@localhost \
    --to=cristiano.p@solnet.ch \
    --cc=cpufreq@vger.kernel.org \
    --cc=davej@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox