0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/types.h>
0009 #include <linux/errno.h>
0010 #include <linux/kernel.h>
0011 #include <linux/slab.h>
0012 #include <linux/init.h>
0013 #include <linux/wait.h>
0014 #include <linux/i2c.h>
0015 #include <linux/mutex.h>
0016
0017 #include <asm/smu.h>
0018 #include <asm/pmac_low_i2c.h>
0019
0020 #include "windfarm.h"
0021
0022 #define VERSION "1.0"
0023
0024
0025 #define MAX_AGE msecs_to_jiffies(800)
0026
0027 struct wf_sat {
0028 struct kref ref;
0029 int nr;
0030 struct mutex mutex;
0031 unsigned long last_read;
0032 u8 cache[16];
0033 struct list_head sensors;
0034 struct i2c_client *i2c;
0035 struct device_node *node;
0036 };
0037
0038 static struct wf_sat *sats[2];
0039
0040 struct wf_sat_sensor {
0041 struct list_head link;
0042 int index;
0043 int index2;
0044 int shift;
0045 struct wf_sat *sat;
0046 struct wf_sensor sens;
0047 };
0048
0049 #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens)
0050
0051 struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
0052 unsigned int *size)
0053 {
0054 struct wf_sat *sat;
0055 int err;
0056 unsigned int i, len;
0057 u8 *buf;
0058 u8 data[4];
0059
0060
0061
0062 if (sat_id > 1 || (sat = sats[sat_id]) == NULL)
0063 return NULL;
0064
0065 err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8);
0066 if (err) {
0067 printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err);
0068 return NULL;
0069 }
0070
0071 err = i2c_smbus_read_word_data(sat->i2c, 9);
0072 if (err < 0) {
0073 printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n");
0074 return NULL;
0075 }
0076 len = err;
0077 if (len == 0) {
0078 printk(KERN_ERR "smu_sat_get_sdb_part no partition %x\n", id);
0079 return NULL;
0080 }
0081
0082 len = le16_to_cpu(len);
0083 len = (len + 3) & ~3;
0084 buf = kmalloc(len, GFP_KERNEL);
0085 if (buf == NULL)
0086 return NULL;
0087
0088 for (i = 0; i < len; i += 4) {
0089 err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data);
0090 if (err < 0) {
0091 printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n",
0092 err);
0093 goto fail;
0094 }
0095 buf[i] = data[1];
0096 buf[i+1] = data[0];
0097 buf[i+2] = data[3];
0098 buf[i+3] = data[2];
0099 }
0100
0101 printk(KERN_DEBUG "sat %d partition %x:", sat_id, id);
0102 print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET,
0103 16, 1, buf, len, false);
0104 if (size)
0105 *size = len;
0106 return (struct smu_sdbp_header *) buf;
0107
0108 fail:
0109 kfree(buf);
0110 return NULL;
0111 }
0112 EXPORT_SYMBOL_GPL(smu_sat_get_sdb_partition);
0113
0114
0115 static int wf_sat_read_cache(struct wf_sat *sat)
0116 {
0117 int err;
0118
0119 err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache);
0120 if (err < 0)
0121 return err;
0122 sat->last_read = jiffies;
0123
0124 #ifdef LOTSA_DEBUG
0125 {
0126 int i;
0127 printk(KERN_DEBUG "wf_sat_get: data is");
0128 print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET,
0129 16, 1, sat->cache, 16, false);
0130 }
0131 #endif
0132 return 0;
0133 }
0134
0135 static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
0136 {
0137 struct wf_sat_sensor *sens = wf_to_sat(sr);
0138 struct wf_sat *sat = sens->sat;
0139 int i, err;
0140 s32 val;
0141
0142 if (sat->i2c == NULL)
0143 return -ENODEV;
0144
0145 mutex_lock(&sat->mutex);
0146 if (time_after(jiffies, (sat->last_read + MAX_AGE))) {
0147 err = wf_sat_read_cache(sat);
0148 if (err)
0149 goto fail;
0150 }
0151
0152 i = sens->index * 2;
0153 val = ((sat->cache[i] << 8) + sat->cache[i+1]) << sens->shift;
0154 if (sens->index2 >= 0) {
0155 i = sens->index2 * 2;
0156
0157 val = (val * ((sat->cache[i] << 8) + sat->cache[i+1])) >> 4;
0158 }
0159
0160 *value = val;
0161 err = 0;
0162
0163 fail:
0164 mutex_unlock(&sat->mutex);
0165 return err;
0166 }
0167
0168 static void wf_sat_release(struct kref *ref)
0169 {
0170 struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
0171
0172 if (sat->nr >= 0)
0173 sats[sat->nr] = NULL;
0174 kfree(sat);
0175 }
0176
0177 static void wf_sat_sensor_release(struct wf_sensor *sr)
0178 {
0179 struct wf_sat_sensor *sens = wf_to_sat(sr);
0180 struct wf_sat *sat = sens->sat;
0181
0182 kfree(sens);
0183 kref_put(&sat->ref, wf_sat_release);
0184 }
0185
0186 static const struct wf_sensor_ops wf_sat_ops = {
0187 .get_value = wf_sat_sensor_get,
0188 .release = wf_sat_sensor_release,
0189 .owner = THIS_MODULE,
0190 };
0191
0192 static int wf_sat_probe(struct i2c_client *client,
0193 const struct i2c_device_id *id)
0194 {
0195 struct device_node *dev = client->dev.of_node;
0196 struct wf_sat *sat;
0197 struct wf_sat_sensor *sens;
0198 const u32 *reg;
0199 const char *loc;
0200 u8 chip, core;
0201 struct device_node *child;
0202 int shift, cpu, index;
0203 char *name;
0204 int vsens[2], isens[2];
0205
0206 sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL);
0207 if (sat == NULL)
0208 return -ENOMEM;
0209 sat->nr = -1;
0210 sat->node = of_node_get(dev);
0211 kref_init(&sat->ref);
0212 mutex_init(&sat->mutex);
0213 sat->i2c = client;
0214 INIT_LIST_HEAD(&sat->sensors);
0215 i2c_set_clientdata(client, sat);
0216
0217 vsens[0] = vsens[1] = -1;
0218 isens[0] = isens[1] = -1;
0219 for_each_child_of_node(dev, child) {
0220 reg = of_get_property(child, "reg", NULL);
0221 loc = of_get_property(child, "location", NULL);
0222 if (reg == NULL || loc == NULL)
0223 continue;
0224
0225
0226 if (*reg < 0x30 || *reg > 0x37)
0227 continue;
0228 index = *reg - 0x30;
0229
0230
0231 if (strncmp(loc, "CPU ", 4) != 0)
0232 continue;
0233 chip = loc[4] - 'A';
0234 core = loc[5] - '0';
0235 if (chip > 1 || core > 1) {
0236 printk(KERN_ERR "wf_sat_create: don't understand "
0237 "location %s for %pOF\n", loc, child);
0238 continue;
0239 }
0240 cpu = 2 * chip + core;
0241 if (sat->nr < 0)
0242 sat->nr = chip;
0243 else if (sat->nr != chip) {
0244 printk(KERN_ERR "wf_sat_create: can't cope with "
0245 "multiple CPU chips on one SAT (%s)\n", loc);
0246 continue;
0247 }
0248
0249 if (of_node_is_type(child, "voltage-sensor")) {
0250 name = "cpu-voltage";
0251 shift = 4;
0252 vsens[core] = index;
0253 } else if (of_node_is_type(child, "current-sensor")) {
0254 name = "cpu-current";
0255 shift = 8;
0256 isens[core] = index;
0257 } else if (of_node_is_type(child, "temp-sensor")) {
0258 name = "cpu-temp";
0259 shift = 10;
0260 } else
0261 continue;
0262
0263
0264 sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL);
0265 if (sens == NULL) {
0266 printk(KERN_ERR "wf_sat_create: couldn't create "
0267 "%s sensor %d (no memory)\n", name, cpu);
0268 continue;
0269 }
0270 sens->index = index;
0271 sens->index2 = -1;
0272 sens->shift = shift;
0273 sens->sat = sat;
0274 sens->sens.ops = &wf_sat_ops;
0275 sens->sens.name = (char *) (sens + 1);
0276 snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu);
0277
0278 if (wf_register_sensor(&sens->sens))
0279 kfree(sens);
0280 else {
0281 list_add(&sens->link, &sat->sensors);
0282 kref_get(&sat->ref);
0283 }
0284 }
0285
0286
0287 for (core = 0; core < 2; ++core) {
0288 if (vsens[core] < 0 || isens[core] < 0)
0289 continue;
0290 cpu = 2 * sat->nr + core;
0291 sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL);
0292 if (sens == NULL) {
0293 printk(KERN_ERR "wf_sat_create: couldn't create power "
0294 "sensor %d (no memory)\n", cpu);
0295 continue;
0296 }
0297 sens->index = vsens[core];
0298 sens->index2 = isens[core];
0299 sens->shift = 0;
0300 sens->sat = sat;
0301 sens->sens.ops = &wf_sat_ops;
0302 sens->sens.name = (char *) (sens + 1);
0303 snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu);
0304
0305 if (wf_register_sensor(&sens->sens))
0306 kfree(sens);
0307 else {
0308 list_add(&sens->link, &sat->sensors);
0309 kref_get(&sat->ref);
0310 }
0311 }
0312
0313 if (sat->nr >= 0)
0314 sats[sat->nr] = sat;
0315
0316 return 0;
0317 }
0318
0319 static int wf_sat_remove(struct i2c_client *client)
0320 {
0321 struct wf_sat *sat = i2c_get_clientdata(client);
0322 struct wf_sat_sensor *sens;
0323
0324
0325 while(!list_empty(&sat->sensors)) {
0326 sens = list_first_entry(&sat->sensors,
0327 struct wf_sat_sensor, link);
0328 list_del(&sens->link);
0329 wf_unregister_sensor(&sens->sens);
0330 }
0331 sat->i2c = NULL;
0332 kref_put(&sat->ref, wf_sat_release);
0333
0334 return 0;
0335 }
0336
0337 static const struct i2c_device_id wf_sat_id[] = {
0338 { "MAC,smu-sat", 0 },
0339 { }
0340 };
0341 MODULE_DEVICE_TABLE(i2c, wf_sat_id);
0342
0343 static const struct of_device_id wf_sat_of_id[] = {
0344 { .compatible = "smu-sat", },
0345 { }
0346 };
0347 MODULE_DEVICE_TABLE(of, wf_sat_of_id);
0348
0349 static struct i2c_driver wf_sat_driver = {
0350 .driver = {
0351 .name = "wf_smu_sat",
0352 .of_match_table = wf_sat_of_id,
0353 },
0354 .probe = wf_sat_probe,
0355 .remove = wf_sat_remove,
0356 .id_table = wf_sat_id,
0357 };
0358
0359 module_i2c_driver(wf_sat_driver);
0360
0361 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
0362 MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
0363 MODULE_LICENSE("GPL");