/drivers/macintosh/windfarm_smu_sensors.c
C | 483 lines | 358 code | 79 blank | 46 comment | 71 complexity | bd92478a9687e408d88297dac2080e6e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * Windfarm PowerMac thermal control. SMU based sensors
- *
- * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
- * <benh@kernel.crashing.org>
- *
- * Released under the term of the GNU GPL v2.
- */
- #include <linux/types.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/wait.h>
- #include <linux/completion.h>
- #include <asm/prom.h>
- #include <asm/machdep.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #include <asm/sections.h>
- #include <asm/smu.h>
- #include "windfarm.h"
- #define VERSION "0.2"
- #undef DEBUG
- #ifdef DEBUG
- #define DBG(args...) printk(args)
- #else
- #define DBG(args...) do { } while(0)
- #endif
- /*
- * Various SMU "partitions" calibration objects for which we
- * keep pointers here for use by bits & pieces of the driver
- */
- static struct smu_sdbp_cpuvcp *cpuvcp;
- static int cpuvcp_version;
- static struct smu_sdbp_cpudiode *cpudiode;
- static struct smu_sdbp_slotspow *slotspow;
- static u8 *debugswitches;
- /*
- * SMU basic sensors objects
- */
- static LIST_HEAD(smu_ads);
- struct smu_ad_sensor {
- struct list_head link;
- u32 reg; /* index in SMU */
- struct wf_sensor sens;
- };
- #define to_smu_ads(c) container_of(c, struct smu_ad_sensor, sens)
- static void smu_ads_release(struct wf_sensor *sr)
- {
- struct smu_ad_sensor *ads = to_smu_ads(sr);
- kfree(ads);
- }
- static int smu_read_adc(u8 id, s32 *value)
- {
- struct smu_simple_cmd cmd;
- DECLARE_COMPLETION_ONSTACK(comp);
- int rc;
- rc = smu_queue_simple(&cmd, SMU_CMD_READ_ADC, 1,
- smu_done_complete, &comp, id);
- if (rc)
- return rc;
- wait_for_completion(&comp);
- if (cmd.cmd.status != 0)
- return cmd.cmd.status;
- if (cmd.cmd.reply_len != 2) {
- printk(KERN_ERR "winfarm: read ADC 0x%x returned %d bytes !\n",
- id, cmd.cmd.reply_len);
- return -EIO;
- }
- *value = *((u16 *)cmd.buffer);
- return 0;
- }
- static int smu_cputemp_get(struct wf_sensor *sr, s32 *value)
- {
- struct smu_ad_sensor *ads = to_smu_ads(sr);
- int rc;
- s32 val;
- s64 scaled;
- rc = smu_read_adc(ads->reg, &val);
- if (rc) {
- printk(KERN_ERR "windfarm: read CPU temp failed, err %d\n",
- rc);
- return rc;
- }
- /* Ok, we have to scale & adjust, taking units into account */
- scaled = (s64)(((u64)val) * (u64)cpudiode->m_value);
- scaled >>= 3;
- scaled += ((s64)cpudiode->b_value) << 9;
- *value = (s32)(scaled << 1);
- return 0;
- }
- static int smu_cpuamp_get(struct wf_sensor *sr, s32 *value)
- {
- struct smu_ad_sensor *ads = to_smu_ads(sr);
- s32 val, scaled;
- int rc;
- rc = smu_read_adc(ads->reg, &val);
- if (rc) {
- printk(KERN_ERR "windfarm: read CPU current failed, err %d\n",
- rc);
- return rc;
- }
- /* Ok, we have to scale & adjust, taking units into account */
- scaled = (s32)(val * (u32)cpuvcp->curr_scale);
- scaled += (s32)cpuvcp->curr_offset;
- *value = scaled << 4;
- return 0;
- }
- static int smu_cpuvolt_get(struct wf_sensor *sr, s32 *value)
- {
- struct smu_ad_sensor *ads = to_smu_ads(sr);
- s32 val, scaled;
- int rc;
- rc = smu_read_adc(ads->reg, &val);
- if (rc) {
- printk(KERN_ERR "windfarm: read CPU voltage failed, err %d\n",
- rc);
- return rc;
- }
- /* Ok, we have to scale & adjust, taking units into account */
- scaled = (s32)(val * (u32)cpuvcp->volt_scale);
- scaled += (s32)cpuvcp->volt_offset;
- *value = scaled << 4;
- return 0;
- }
- static int smu_slotspow_get(struct wf_sensor *sr, s32 *value)
- {
- struct smu_ad_sensor *ads = to_smu_ads(sr);
- s32 val, scaled;
- int rc;
- rc = smu_read_adc(ads->reg, &val);
- if (rc) {
- printk(KERN_ERR "windfarm: read slots power failed, err %d\n",
- rc);
- return rc;
- }
- /* Ok, we have to scale & adjust, taking units into account */
- scaled = (s32)(val * (u32)slotspow->pow_scale);
- scaled += (s32)slotspow->pow_offset;
- *value = scaled << 4;
- return 0;
- }
- static struct wf_sensor_ops smu_cputemp_ops = {
- .get_value = smu_cputemp_get,
- .release = smu_ads_release,
- .owner = THIS_MODULE,
- };
- static struct wf_sensor_ops smu_cpuamp_ops = {
- .get_value = smu_cpuamp_get,
- .release = smu_ads_release,
- .owner = THIS_MODULE,
- };
- static struct wf_sensor_ops smu_cpuvolt_ops = {
- .get_value = smu_cpuvolt_get,
- .release = smu_ads_release,
- .owner = THIS_MODULE,
- };
- static struct wf_sensor_ops smu_slotspow_ops = {
- .get_value = smu_slotspow_get,
- .release = smu_ads_release,
- .owner = THIS_MODULE,
- };
- static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
- {
- struct smu_ad_sensor *ads;
- const char *c, *l;
- const u32 *v;
- ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
- if (ads == NULL)
- return NULL;
- c = of_get_property(node, "device_type", NULL);
- l = of_get_property(node, "location", NULL);
- if (c == NULL || l == NULL)
- goto fail;
- /* We currently pick the sensors based on the OF name and location
- * properties, while Darwin uses the sensor-id's.
- * The problem with the IDs is that they are model specific while it
- * looks like apple has been doing a reasonably good job at keeping
- * the names and locations consistents so I'll stick with the names
- * and locations for now.
- */
- if (!strcmp(c, "temp-sensor") &&
- !strcmp(l, "CPU T-Diode")) {
- ads->sens.ops = &smu_cputemp_ops;
- ads->sens.name = "cpu-temp";
- if (cpudiode == NULL) {
- DBG("wf: cpudiode partition (%02x) not found\n",
- SMU_SDB_CPUDIODE_ID);
- goto fail;
- }
- } else if (!strcmp(c, "current-sensor") &&
- !strcmp(l, "CPU Current")) {
- ads->sens.ops = &smu_cpuamp_ops;
- ads->sens.name = "cpu-current";
- if (cpuvcp == NULL) {
- DBG("wf: cpuvcp partition (%02x) not found\n",
- SMU_SDB_CPUVCP_ID);
- goto fail;
- }
- } else if (!strcmp(c, "voltage-sensor") &&
- !strcmp(l, "CPU Voltage")) {
- ads->sens.ops = &smu_cpuvolt_ops;
- ads->sens.name = "cpu-voltage";
- if (cpuvcp == NULL) {
- DBG("wf: cpuvcp partition (%02x) not found\n",
- SMU_SDB_CPUVCP_ID);
- goto fail;
- }
- } else if (!strcmp(c, "power-sensor") &&
- !strcmp(l, "Slots Power")) {
-