Commit 5787e471 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] cpufreq (1/5): x86 driver updates #1 (elanfreq, gx-suspmod, powernow-k6)

- switch the AMD Elan, AMD PowerNow-K6 and the Cyrix/MediaGX driver
  to use the advanced cpufreq_driver registration process
- cleanups
parent e4caae91
...@@ -31,15 +31,11 @@ ...@@ -31,15 +31,11 @@
#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ #define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */
#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ #define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */
static struct cpufreq_driver *elanfreq_driver; static struct cpufreq_driver elanfreq_driver;
/* Module parameter */ /* Module parameter */
static int max_freq; static int max_freq;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
struct s_elan_multiplier { struct s_elan_multiplier {
int clock; /* frequency in kHz */ int clock; /* frequency in kHz */
int val40h; /* PMU Force Mode register */ int val40h; /* PMU Force Mode register */
...@@ -127,11 +123,6 @@ static void elanfreq_set_cpu_state (unsigned int state) { ...@@ -127,11 +123,6 @@ static void elanfreq_set_cpu_state (unsigned int state) {
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
if (!elanfreq_driver) {
printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
return;
}
freqs.old = elanfreq_get_cpu_frequency(); freqs.old = elanfreq_get_cpu_frequency();
freqs.new = elan_multiplier[state].clock; freqs.new = elan_multiplier[state].clock;
freqs.cpu = 0; /* elanfreq.c is UP only driver */ freqs.cpu = 0; /* elanfreq.c is UP only driver */
...@@ -187,11 +178,13 @@ static int elanfreq_verify (struct cpufreq_policy *policy) ...@@ -187,11 +178,13 @@ static int elanfreq_verify (struct cpufreq_policy *policy)
return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]); return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]);
} }
static int elanfreq_setpolicy (struct cpufreq_policy *policy) static int elanfreq_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
if (cpufreq_frequency_table_setpolicy(policy, &elanfreq_table[0], &newstate)) if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
elanfreq_set_cpu_state(newstate); elanfreq_set_cpu_state(newstate);
...@@ -204,6 +197,37 @@ static int elanfreq_setpolicy (struct cpufreq_policy *policy) ...@@ -204,6 +197,37 @@ static int elanfreq_setpolicy (struct cpufreq_policy *policy)
* Module init and exit code * Module init and exit code
*/ */
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
unsigned int i;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
(c->x86 != 4) || (c->x86_model!=10))
return -ENODEV;
/* max freq */
if (!max_freq)
max_freq = elanfreq_get_cpu_frequency();
/* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
/* cpuinfo and default policy values */
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
#ifdef CONFIG_CPU_FREQ_24_API
elanfreq_driver.cpu_cur_freq[policy->cpu] = elanfreq_get_cpu_frequency();
#endif
return cpufreq_frequency_table_cpuinfo(policy, &elanfreq_table[0]);;
}
#ifndef MODULE #ifndef MODULE
/** /**
* elanfreq_setup - elanfreq command line parameter parsing * elanfreq_setup - elanfreq command line parameter parsing
...@@ -224,11 +248,18 @@ static int __init elanfreq_setup(char *str) ...@@ -224,11 +248,18 @@ static int __init elanfreq_setup(char *str)
__setup("elanfreq=", elanfreq_setup); __setup("elanfreq=", elanfreq_setup);
#endif #endif
static struct cpufreq_driver elanfreq_driver = {
.verify = elanfreq_verify,
.target = elanfreq_target,
.init = elanfreq_cpu_init,
.name = "elanfreq",
};
static int __init elanfreq_init(void) static int __init elanfreq_init(void)
{ {
struct cpuinfo_x86 *c = cpu_data; struct cpuinfo_x86 *c = cpu_data;
struct cpufreq_driver *driver;
int ret, i;
/* Test if we have the right hardware */ /* Test if we have the right hardware */
if ((c->x86_vendor != X86_VENDOR_AMD) || if ((c->x86_vendor != X86_VENDOR_AMD) ||
...@@ -238,63 +269,22 @@ static int __init elanfreq_init(void) ...@@ -238,63 +269,22 @@ static int __init elanfreq_init(void)
return -ENODEV; return -ENODEV;
} }
driver = kmalloc(sizeof(struct cpufreq_driver) + return cpufreq_register_driver(&elanfreq_driver);
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver)
return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1);
if (!max_freq)
max_freq = elanfreq_get_cpu_frequency();
/* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = elanfreq_get_cpu_frequency();
#endif
driver->verify = &elanfreq_verify;
driver->setpolicy = &elanfreq_setpolicy;
strncpy(driver->name, "elanfreq", CPUFREQ_NAME_LEN);
driver->policy[0].cpu = 0;
ret = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &elanfreq_table[0]);
if (ret) {
kfree(driver);
return ret;
}
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
elanfreq_driver = driver;
ret = cpufreq_register(driver);
if (ret) {
elanfreq_driver = NULL;
kfree(driver);
}
return ret;
} }
static void __exit elanfreq_exit(void) static void __exit elanfreq_exit(void)
{ {
if (elanfreq_driver) { cpufreq_unregister_driver(&elanfreq_driver);
cpufreq_unregister();
kfree(elanfreq_driver);
}
} }
module_init(elanfreq_init);
module_exit(elanfreq_exit);
MODULE_PARM (max_freq, "i"); MODULE_PARM (max_freq, "i");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
module_init(elanfreq_init);
module_exit(elanfreq_exit);
...@@ -106,6 +106,8 @@ ...@@ -106,6 +106,8 @@
#define PWRSVE_ISA (1<<3) /* stop ISA clock */ #define PWRSVE_ISA (1<<3) /* stop ISA clock */
#define PWRSVE (1<<4) /* active idle */ #define PWRSVE (1<<4) /* active idle */
static struct cpufreq_driver gx_suspmod_driver;
struct gxfreq_params { struct gxfreq_params {
u8 on_duration; u8 on_duration;
u8 off_duration; u8 off_duration;
...@@ -116,7 +118,6 @@ struct gxfreq_params { ...@@ -116,7 +118,6 @@ struct gxfreq_params {
struct pci_dev *cs55x0; struct pci_dev *cs55x0;
}; };
static struct cpufreq_driver *gx_driver;
static struct gxfreq_params *gx_params; static struct gxfreq_params *gx_params;
static int stock_freq; static int stock_freq;
...@@ -345,7 +346,7 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy) ...@@ -345,7 +346,7 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
unsigned int tmp_freq = 0; unsigned int tmp_freq = 0;
u8 tmp1, tmp2; u8 tmp1, tmp2;
if (!gx_driver || !stock_freq || !policy) if (!stock_freq || !policy)
return -EINVAL; return -EINVAL;
policy->cpu = 0; policy->cpu = 0;
...@@ -375,33 +376,73 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy) ...@@ -375,33 +376,73 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
} }
/* /*
* cpufreq_gx_setpolicy: * cpufreq_gx_target:
* *
*/ */
static int cpufreq_gx_setpolicy(struct cpufreq_policy *policy) static int cpufreq_gx_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{ {
u8 tmp1, tmp2;
unsigned int tmp_freq;
if (!gx_driver || !stock_freq || !policy) if (!stock_freq || !policy)
return -EINVAL; return -EINVAL;
policy->cpu = 0; policy->cpu = 0;
if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2);
/* here we need to make sure that we don't set the
* frequency below policy->min (see comment in
* cpufreq_gx_verify() - guarantee of processing
* capacity.
*/
u8 tmp1, tmp2;
unsigned int tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2);
while (tmp_freq < policy->min) { while (tmp_freq < policy->min) {
tmp_freq += stock_freq / max_duration; tmp_freq += stock_freq / max_duration;
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
} }
while (tmp_freq > policy->max) {
tmp_freq -= stock_freq / max_duration;
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
}
gx_set_cpuspeed(tmp_freq); gx_set_cpuspeed(tmp_freq);
return 0;
}
static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
{
int maxfreq, curfreq;
if (!policy || policy->cpu != 0)
return -ENODEV;
/* determine maximum frequency */
if (pci_busclk) {
maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} else if (cpu_khz) {
maxfreq = cpu_khz;
} else { } else {
gx_set_cpuspeed(policy->max); maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} }
stock_freq = maxfreq;
curfreq = gx_get_cpuspeed();
dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq);
/* setup basic struct for cpufreq API */
policy->cpu = 0;
if (max_duration < POLICY_MIN_DIV)
policy->min = maxfreq / max_duration;
else
policy->min = maxfreq / POLICY_MIN_DIV;
policy->max = maxfreq;
#ifdef CONFIG_CPU_FREQ_24_API
gx_suspmod_driver.cpu_cur_freq[policy->cpu] = curfreq;
#endif
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.min_freq = maxfreq / max_duration;
policy->cpuinfo.max_freq = maxfreq;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
return 0; return 0;
} }
...@@ -409,11 +450,16 @@ static int cpufreq_gx_setpolicy(struct cpufreq_policy *policy) ...@@ -409,11 +450,16 @@ static int cpufreq_gx_setpolicy(struct cpufreq_policy *policy)
* cpufreq_gx_init: * cpufreq_gx_init:
* MediaGX/Geode GX initilize cpufreq driver * MediaGX/Geode GX initilize cpufreq driver
*/ */
static struct cpufreq_driver gx_suspmod_driver = {
.verify = cpufreq_gx_verify,
.target = cpufreq_gx_target,
.init = cpufreq_gx_cpu_init,
.name = "gx-suspmod",
};
static int __init cpufreq_gx_init(void) static int __init cpufreq_gx_init(void)
{ {
int maxfreq,ret,curfreq; int ret;
struct cpufreq_driver *driver;
struct gxfreq_params *params; struct gxfreq_params *params;
struct pci_dev *gx_pci; struct pci_dev *gx_pci;
u32 class_rev; u32 class_rev;
...@@ -428,21 +474,13 @@ static int __init cpufreq_gx_init(void) ...@@ -428,21 +474,13 @@ static int __init cpufreq_gx_init(void)
dprintk("geode suspend modulation available.\n"); dprintk("geode suspend modulation available.\n");
driver = kmalloc(sizeof(struct cpufreq_driver) + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (driver == NULL)
return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
params = kmalloc(sizeof(struct gxfreq_params), GFP_KERNEL); params = kmalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
if (params == NULL) { if (params == NULL)
kfree(driver);
return -ENOMEM; return -ENOMEM;
}
memset(params, 0, sizeof(struct gxfreq_params)); memset(params, 0, sizeof(struct gxfreq_params));
driver->policy = (struct cpufreq_policy *)(driver + 1);
params->cs55x0 = gx_pci; params->cs55x0 = gx_pci;
gx_params = params;
/* keep cs55x0 configurations */ /* keep cs55x0 configurations */
pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg)); pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg));
...@@ -453,45 +491,7 @@ static int __init cpufreq_gx_init(void) ...@@ -453,45 +491,7 @@ static int __init cpufreq_gx_init(void)
pci_read_config_dword(params->cs55x0, PCI_CLASS_REVISION, &class_rev); pci_read_config_dword(params->cs55x0, PCI_CLASS_REVISION, &class_rev);
params->pci_rev = class_rev && 0xff; params->pci_rev = class_rev && 0xff;
gx_params = params; if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) {
/* determine maximum frequency */
if (pci_busclk) {
maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} else if (cpu_khz) {
maxfreq = cpu_khz;
} else {
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
}
stock_freq = maxfreq;
curfreq = gx_get_cpuspeed();
dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq);
/* setup basic struct for cpufreq API */
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = curfreq;
#endif
driver->policy[0].cpu = 0;
if (max_duration < POLICY_MIN_DIV)
driver->policy[0].min = maxfreq / max_duration;
else
driver->policy[0].min = maxfreq / POLICY_MIN_DIV;
driver->policy[0].max = maxfreq;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.min_freq = maxfreq / max_duration;
driver->policy[0].cpuinfo.max_freq = maxfreq;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->verify = &cpufreq_gx_verify;
driver->setpolicy = &cpufreq_gx_setpolicy;
strncpy(driver->name, "gx-suspmod", CPUFREQ_NAME_LEN);
gx_driver = driver;
if ((ret = cpufreq_register(driver))) {
kfree(driver);
kfree(params); kfree(params);
return ret; /* register error! */ return ret; /* register error! */
} }
...@@ -501,13 +501,8 @@ static int __init cpufreq_gx_init(void) ...@@ -501,13 +501,8 @@ static int __init cpufreq_gx_init(void)
static void __exit cpufreq_gx_exit(void) static void __exit cpufreq_gx_exit(void)
{ {
if (gx_driver) { cpufreq_unregister_driver(&gx_suspmod_driver);
/* disable throttling */
gx_set_cpuspeed(stock_freq);
cpufreq_unregister();
kfree(gx_driver);
kfree(gx_params); kfree(gx_params);
}
} }
MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>"); MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>");
......
/* /*
* $Id: powernow-k6.c,v 1.36 2002/10/31 21:17:40 db Exp $ * $Id: powernow-k6.c,v 1.46 2003/01/20 17:31:47 db Exp $
* This file was part of Powertweak Linux (http://powertweak.sf.net) * This file was part of Powertweak Linux (http://powertweak.sf.net)
* and is shared with the Linux Kernel module. * and is shared with the Linux Kernel module.
* *
* (C) 2000-2002 Dave Jones, Arjan van de Ven, Janne Pnkl, Dominik Brodowski. * (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pnkl, Dominik Brodowski.
* *
* Licensed under the terms of the GNU GPL License version 2. * Licensed under the terms of the GNU GPL License version 2.
* *
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long #define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
as it is unused */ as it is unused */
static struct cpufreq_driver *powernow_driver; static struct cpufreq_driver powernow_k6_driver;
static unsigned int busfreq; /* FSB, in 10 kHz */ static unsigned int busfreq; /* FSB, in 10 kHz */
static unsigned int max_multiplier; static unsigned int max_multiplier;
...@@ -77,8 +77,8 @@ static void powernow_k6_set_state (unsigned int best_i) ...@@ -77,8 +77,8 @@ static void powernow_k6_set_state (unsigned int best_i)
unsigned long msrval; unsigned long msrval;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
if (!powernow_driver) { if (clock_ratio[best_i].index > max_multiplier) {
printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n"); printk(KERN_ERR "cpufreq: invalid target frequency\n");
return; return;
} }
...@@ -126,11 +126,13 @@ static int powernow_k6_verify(struct cpufreq_policy *policy) ...@@ -126,11 +126,13 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
* *
* sets a new CPUFreq policy * sets a new CPUFreq policy
*/ */
static int powernow_k6_setpolicy (struct cpufreq_policy *policy) static int powernow_k6_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
if (cpufreq_frequency_table_setpolicy(policy, &clock_ratio[0], &newstate)) if (cpufreq_frequency_table_target(policy, &clock_ratio[0], target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
powernow_k6_set_state(newstate); powernow_k6_set_state(newstate);
...@@ -139,43 +141,22 @@ static int powernow_k6_setpolicy (struct cpufreq_policy *policy) ...@@ -139,43 +141,22 @@ static int powernow_k6_setpolicy (struct cpufreq_policy *policy)
} }
/** static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
* powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
*
* Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
* devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
* on success.
*/
static int __init powernow_k6_init(void)
{ {
struct cpuinfo_x86 *c = cpu_data; struct cpuinfo_x86 *c = cpu_data;
struct cpufreq_driver *driver;
unsigned int result;
unsigned int i; unsigned int i;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13))) ((c->x86_model != 12) && (c->x86_model != 13)))
return -ENODEV; return -ENODEV;
if (policy->cpu != 0)
return -ENODEV;
/* get frequencies */
max_multiplier = powernow_k6_get_cpu_multiplier(); max_multiplier = powernow_k6_get_cpu_multiplier();
busfreq = cpu_khz / max_multiplier; busfreq = cpu_khz / max_multiplier;
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
printk("cpufreq: PowerNow IOPORT region already used.\n");
return -EIO;
}
/* initialization of main "cpufreq" code*/
driver = kmalloc(sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) {
release_region (POWERNOW_IOPORT, 16);
return -ENOMEM;
}
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1);
/* table init */ /* table init */
for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
if (clock_ratio[i].index > max_multiplier) if (clock_ratio[i].index > max_multiplier)
...@@ -184,33 +165,63 @@ static int __init powernow_k6_init(void) ...@@ -184,33 +165,63 @@ static int __init powernow_k6_init(void)
clock_ratio[i].frequency = busfreq * clock_ratio[i].index; clock_ratio[i].frequency = busfreq * clock_ratio[i].index;
} }
driver->verify = &powernow_k6_verify;
driver->setpolicy = &powernow_k6_setpolicy;
strncpy(driver->name, "powernow-k6", CPUFREQ_NAME_LEN);
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
driver->policy[0].cpu = 0; policy->policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = busfreq * max_multiplier; powernow_k6_driver.cpu_cur_freq[policy->cpu] = busfreq * max_multiplier;
#endif #endif
result = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &clock_ratio[0]);
if (result) { return cpufreq_frequency_table_cpuinfo(policy, &clock_ratio[0]);
kfree(driver); }
return result;
static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
{
unsigned int i;
for (i=0; i<8; i++) {
if (i==max_multiplier)
powernow_k6_set_state(i);
} }
return 0;
}
static struct cpufreq_driver powernow_k6_driver = {
.verify = powernow_k6_verify,
.target = powernow_k6_target,
.init = powernow_k6_cpu_init,
.exit = powernow_k6_cpu_exit,
.name = "powernow-k6",
};
powernow_driver = driver;
result = cpufreq_register(driver); /**
if (result) { * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
*
* Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
* devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
* on success.
*/
static int __init powernow_k6_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13)))
return -ENODEV;
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
printk("cpufreq: PowerNow IOPORT region already used.\n");
return -EIO;
}
if (cpufreq_register_driver(&powernow_k6_driver)) {
release_region (POWERNOW_IOPORT, 16); release_region (POWERNOW_IOPORT, 16);
powernow_driver = NULL; return -EINVAL;
kfree(driver);
} }
return result; return 0;
} }
...@@ -221,20 +232,14 @@ static int __init powernow_k6_init(void) ...@@ -221,20 +232,14 @@ static int __init powernow_k6_init(void)
*/ */
static void __exit powernow_k6_exit(void) static void __exit powernow_k6_exit(void)
{ {
unsigned int i; cpufreq_unregister_driver(&powernow_k6_driver);
release_region (POWERNOW_IOPORT, 16);
if (powernow_driver) {
for (i=0;i<8;i++)
if (clock_ratio[i].index == max_multiplier)
powernow_k6_set_state(i);
cpufreq_unregister();
kfree(powernow_driver);
}
} }
MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors."); MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
module_init(powernow_k6_init); module_init(powernow_k6_init);
module_exit(powernow_k6_exit); module_exit(powernow_k6_exit);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment