All of lore.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: 29+ 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  7:43           ` 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.