1ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* 2ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Windfarm PowerMac thermal control. SMU "satellite" controller sensors. 3ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * 4ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org> 5ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * 6ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Released under the terms of the GNU GPL v2. 7ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt */ 8ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 9ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/types.h> 10ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/errno.h> 11ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/kernel.h> 12ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/slab.h> 13ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/init.h> 14ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/wait.h> 15ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/i2c.h> 1656783c5e4dd32ca370ad0bdf3a9c6c1aaee94726Daniel Walker#include <linux/mutex.h> 17ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/prom.h> 18ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/smu.h> 19ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/pmac_low_i2c.h> 20ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 21ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include "windfarm.h" 22ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 23e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt#define VERSION "1.0" 24ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 25ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define DEBUG 26ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 27ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#ifdef DEBUG 28ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define DBG(args...) printk(args) 29ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#else 30ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define DBG(args...) do { } while(0) 31ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#endif 32ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 33ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* If the cache is older than 800ms we'll refetch it */ 34ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define MAX_AGE msecs_to_jiffies(800) 35ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 36ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstruct wf_sat { 37e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct kref ref; 38ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int nr; 3956783c5e4dd32ca370ad0bdf3a9c6c1aaee94726Daniel Walker struct mutex mutex; 40ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt unsigned long last_read; /* jiffies when cache last updated */ 41ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt u8 cache[16]; 42e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct list_head sensors; 43351ca3e31197929535418f5affc761cd9fb07428Jean Delvare struct i2c_client *i2c; 44ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct device_node *node; 45ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}; 46ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 47ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic struct wf_sat *sats[2]; 48ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 49ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstruct wf_sat_sensor { 50e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct list_head link; 51e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt int index; 52e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt int index2; /* used for power sensors */ 53e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt int shift; 54e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct wf_sat *sat; 55e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct wf_sensor sens; 56ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}; 57ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 58ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) 59ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 60ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstruct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, 61ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt unsigned int *size) 62ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 63ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat *sat; 64ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int err; 65ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt unsigned int i, len; 66ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt u8 *buf; 67ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt u8 data[4]; 68ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 69ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* TODO: Add the resulting partition to the device-tree */ 70ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 71ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sat_id > 1 || (sat = sats[sat_id]) == NULL) 72ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return NULL; 73ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 74351ca3e31197929535418f5affc761cd9fb07428Jean Delvare err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8); 75ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (err) { 76ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err); 77ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return NULL; 78ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 79ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 80351ca3e31197929535418f5affc761cd9fb07428Jean Delvare err = i2c_smbus_read_word_data(sat->i2c, 9); 812fd091f3eebc5accefa5f77ff04436982765d15croel kluin if (err < 0) { 82ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); 83ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return NULL; 84ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 852fd091f3eebc5accefa5f77ff04436982765d15croel kluin len = err; 86ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (len == 0) { 87ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "smu_sat_get_sdb_part no partition %x\n", id); 88ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return NULL; 89ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 90ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 91ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt len = le16_to_cpu(len); 92ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt len = (len + 3) & ~3; 93ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt buf = kmalloc(len, GFP_KERNEL); 94ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (buf == NULL) 95ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return NULL; 96ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 97ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt for (i = 0; i < len; i += 4) { 98351ca3e31197929535418f5affc761cd9fb07428Jean Delvare err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data); 994b2643d7d9bdcd776749e17f73c168ddf02e93cbJean Delvare if (err < 0) { 100ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", 101ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt err); 102ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt goto fail; 103ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 104ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt buf[i] = data[1]; 105ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt buf[i+1] = data[0]; 106ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt buf[i+2] = data[3]; 107ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt buf[i+3] = data[2]; 108ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 109ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#ifdef DEBUG 110ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id); 111ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt for (i = 0; i < len; ++i) 112ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt DBG(" %x", buf[i]); 113ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt DBG("\n"); 114ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#endif 115ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 116ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (size) 117ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt *size = len; 118ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return (struct smu_sdbp_header *) buf; 119ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 120ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt fail: 121ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt kfree(buf); 122ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return NULL; 123ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 1249127dd1aace4e89acb48fbcafd0ed27d3869847bJohannes BergEXPORT_SYMBOL_GPL(smu_sat_get_sdb_partition); 125ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 126ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* refresh the cache */ 127ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic int wf_sat_read_cache(struct wf_sat *sat) 128ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 129ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int err; 130ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 131351ca3e31197929535418f5affc761cd9fb07428Jean Delvare err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache); 1324b2643d7d9bdcd776749e17f73c168ddf02e93cbJean Delvare if (err < 0) 133ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return err; 134ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sat->last_read = jiffies; 135ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#ifdef LOTSA_DEBUG 136ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt { 137ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int i; 138ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt DBG(KERN_DEBUG "wf_sat_get: data is"); 139ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt for (i = 0; i < 16; ++i) 140ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt DBG(" %.2x", sat->cache[i]); 141ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt DBG("\n"); 142ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 143ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#endif 144ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return 0; 145ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 146ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 147e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidtstatic int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value) 148ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 149ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat_sensor *sens = wf_to_sat(sr); 150ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat *sat = sens->sat; 151ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int i, err; 152ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt s32 val; 153ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 154351ca3e31197929535418f5affc761cd9fb07428Jean Delvare if (sat->i2c == NULL) 155ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return -ENODEV; 156ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 15756783c5e4dd32ca370ad0bdf3a9c6c1aaee94726Daniel Walker mutex_lock(&sat->mutex); 158ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (time_after(jiffies, (sat->last_read + MAX_AGE))) { 159ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt err = wf_sat_read_cache(sat); 160ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (err) 161ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt goto fail; 162ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 163ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 164ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt i = sens->index * 2; 165ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt val = ((sat->cache[i] << 8) + sat->cache[i+1]) << sens->shift; 166ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sens->index2 >= 0) { 167ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt i = sens->index2 * 2; 168ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* 4.12 * 8.8 -> 12.20; shift right 4 to get 16.16 */ 169ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt val = (val * ((sat->cache[i] << 8) + sat->cache[i+1])) >> 4; 170ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 171ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 172ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt *value = val; 173ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt err = 0; 174ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 175ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt fail: 17656783c5e4dd32ca370ad0bdf3a9c6c1aaee94726Daniel Walker mutex_unlock(&sat->mutex); 177ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return err; 178ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 179ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 180e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidtstatic void wf_sat_release(struct kref *ref) 181e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt{ 182e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct wf_sat *sat = container_of(ref, struct wf_sat, ref); 183e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt 184e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt if (sat->nr >= 0) 185e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt sats[sat->nr] = NULL; 186e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt kfree(sat); 187e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt} 188e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt 189e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidtstatic void wf_sat_sensor_release(struct wf_sensor *sr) 190ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 191ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat_sensor *sens = wf_to_sat(sr); 192ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat *sat = sens->sat; 193ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 194ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt kfree(sens); 195e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt kref_put(&sat->ref, wf_sat_release); 196ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 197ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 198ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic struct wf_sensor_ops wf_sat_ops = { 199e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt .get_value = wf_sat_sensor_get, 200e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt .release = wf_sat_sensor_release, 201ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt .owner = THIS_MODULE, 202ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}; 203ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 204351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic int wf_sat_probe(struct i2c_client *client, 205351ca3e31197929535418f5affc761cd9fb07428Jean Delvare const struct i2c_device_id *id) 206351ca3e31197929535418f5affc761cd9fb07428Jean Delvare{ 2079525a08b30b1c8e39578938fc3420ac0b56f3a3dBenjamin Herrenschmidt struct device_node *dev = client->dev.of_node; 208ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat *sat; 209ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sat_sensor *sens; 210018a3d1db7cdb6127656c1622ee1d2302e16436dJeremy Kerr const u32 *reg; 211018a3d1db7cdb6127656c1622ee1d2302e16436dJeremy Kerr const char *loc, *type; 212351ca3e31197929535418f5affc761cd9fb07428Jean Delvare u8 chip, core; 213ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct device_node *child; 214ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int shift, cpu, index; 215ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt char *name; 216ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt int vsens[2], isens[2]; 217ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 218ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL); 219ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sat == NULL) 220351ca3e31197929535418f5affc761cd9fb07428Jean Delvare return -ENOMEM; 221ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sat->nr = -1; 222ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sat->node = of_node_get(dev); 223e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt kref_init(&sat->ref); 22456783c5e4dd32ca370ad0bdf3a9c6c1aaee94726Daniel Walker mutex_init(&sat->mutex); 225351ca3e31197929535418f5affc761cd9fb07428Jean Delvare sat->i2c = client; 226e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt INIT_LIST_HEAD(&sat->sensors); 227351ca3e31197929535418f5affc761cd9fb07428Jean Delvare i2c_set_clientdata(client, sat); 228ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 229ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt vsens[0] = vsens[1] = -1; 230ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt isens[0] = isens[1] = -1; 231ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt child = NULL; 232ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt while ((child = of_get_next_child(dev, child)) != NULL) { 23301b2726dd11ef198ac6cf8f88974b4427d40ffdbStephen Rothwell reg = of_get_property(child, "reg", NULL); 23401b2726dd11ef198ac6cf8f88974b4427d40ffdbStephen Rothwell type = of_get_property(child, "device_type", NULL); 23501b2726dd11ef198ac6cf8f88974b4427d40ffdbStephen Rothwell loc = of_get_property(child, "location", NULL); 236ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (reg == NULL || loc == NULL) 237ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 238ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 239ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* the cooked sensors are between 0x30 and 0x37 */ 240ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (*reg < 0x30 || *reg > 0x37) 241ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 242ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt index = *reg - 0x30; 243ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 244ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* expect location to be CPU [AB][01] ... */ 245ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (strncmp(loc, "CPU ", 4) != 0) 246ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 247ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt chip = loc[4] - 'A'; 248ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt core = loc[5] - '0'; 249ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (chip > 1 || core > 1) { 250ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "wf_sat_create: don't understand " 251ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt "location %s for %s\n", loc, child->full_name); 252ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 253ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 254ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt cpu = 2 * chip + core; 255ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sat->nr < 0) 256ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sat->nr = chip; 257ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt else if (sat->nr != chip) { 258ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "wf_sat_create: can't cope with " 259ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt "multiple CPU chips on one SAT (%s)\n", loc); 260ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 261ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 262ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 263ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (strcmp(type, "voltage-sensor") == 0) { 264ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt name = "cpu-voltage"; 265ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt shift = 4; 266ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt vsens[core] = index; 267ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } else if (strcmp(type, "current-sensor") == 0) { 268ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt name = "cpu-current"; 269ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt shift = 8; 270ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt isens[core] = index; 271ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } else if (strcmp(type, "temp-sensor") == 0) { 272ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt name = "cpu-temp"; 273ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt shift = 10; 274ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } else 275ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; /* hmmm shouldn't happen */ 276ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 277ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* the +16 is enough for "cpu-voltage-n" */ 278ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL); 279ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sens == NULL) { 280ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "wf_sat_create: couldn't create " 281ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt "%s sensor %d (no memory)\n", name, cpu); 282ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 283ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 284ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->index = index; 285ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->index2 = -1; 286ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->shift = shift; 287ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->sat = sat; 288ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->sens.ops = &wf_sat_ops; 289ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->sens.name = (char *) (sens + 1); 29043671cc96e58458b2711f1e97ff24a4c0e7cd1acStephen Rothwell snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu); 291ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 292e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt if (wf_register_sensor(&sens->sens)) 293ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt kfree(sens); 294e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt else { 295e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt list_add(&sens->link, &sat->sensors); 296e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt kref_get(&sat->ref); 297ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 298ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 299ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 300ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* make the power sensors */ 301ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt for (core = 0; core < 2; ++core) { 302ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (vsens[core] < 0 || isens[core] < 0) 303ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 304ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt cpu = 2 * sat->nr + core; 305ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL); 306ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sens == NULL) { 307ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "wf_sat_create: couldn't create power " 308ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt "sensor %d (no memory)\n", cpu); 309ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 310ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 311ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->index = vsens[core]; 312ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->index2 = isens[core]; 313ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->shift = 0; 314ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->sat = sat; 315ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->sens.ops = &wf_sat_ops; 316ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sens->sens.name = (char *) (sens + 1); 31743671cc96e58458b2711f1e97ff24a4c0e7cd1acStephen Rothwell snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu); 318ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 319e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt if (wf_register_sensor(&sens->sens)) 320ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt kfree(sens); 321e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt else { 322e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt list_add(&sens->link, &sat->sensors); 323e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt kref_get(&sat->ref); 324ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 325ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 326ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 327ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (sat->nr >= 0) 328ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt sats[sat->nr] = sat; 329ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 330351ca3e31197929535418f5affc761cd9fb07428Jean Delvare return 0; 331ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 332ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 333351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic int wf_sat_remove(struct i2c_client *client) 334ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 335351ca3e31197929535418f5affc761cd9fb07428Jean Delvare struct wf_sat *sat = i2c_get_clientdata(client); 336e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct wf_sat_sensor *sens; 337ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 338e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt /* release sensors */ 339e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt while(!list_empty(&sat->sensors)) { 340e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt sens = list_first_entry(&sat->sensors, 341e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt struct wf_sat_sensor, link); 342e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt list_del(&sens->link); 343e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt wf_unregister_sensor(&sens->sens); 344e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt } 345351ca3e31197929535418f5affc761cd9fb07428Jean Delvare sat->i2c = NULL; 346e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt kref_put(&sat->ref, wf_sat_release); 347e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt 348ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return 0; 349ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 350ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 351351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic const struct i2c_device_id wf_sat_id[] = { 352e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin Herrenschmidt { "MAC,smu-sat", 0 }, 353351ca3e31197929535418f5affc761cd9fb07428Jean Delvare { } 354351ca3e31197929535418f5affc761cd9fb07428Jean Delvare}; 355e326b30fda9a985a2e7fda6fb9212b86bf025c39Benjamin HerrenschmidtMODULE_DEVICE_TABLE(i2c, wf_sat_id); 356351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 357351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic struct i2c_driver wf_sat_driver = { 358351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .driver = { 359351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .name = "wf_smu_sat", 360351ca3e31197929535418f5affc761cd9fb07428Jean Delvare }, 361351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .probe = wf_sat_probe, 362351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .remove = wf_sat_remove, 363351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .id_table = wf_sat_id, 364351ca3e31197929535418f5affc761cd9fb07428Jean Delvare}; 365351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 366f7fb862b843269d02a2fa75e4bbb49603f801b88Wei Yongjunmodule_i2c_driver(wf_sat_driver); 367ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 368ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); 369ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control"); 370ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_LICENSE("GPL"); 371