1 /* 2 * Windfarm PowerMac thermal control. MAX6690 sensor. 3 * 4 * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org> 5 * 6 * Use and redistribute under the terms of the GNU GPL v2. 7 */ 8 #include <linux/types.h> 9 #include <linux/errno.h> 10 #include <linux/kernel.h> 11 #include <linux/init.h> 12 #include <linux/slab.h> 13 #include <linux/i2c.h> 14 #include <asm/prom.h> 15 #include <asm/pmac_low_i2c.h> 16 17 #include "windfarm.h" 18 19 #define VERSION "1.0" 20 21 /* This currently only exports the external temperature sensor, 22 since that's all the control loops need. */ 23 24 /* Some MAX6690 register numbers */ 25 #define MAX6690_INTERNAL_TEMP 0 26 #define MAX6690_EXTERNAL_TEMP 1 27 28 struct wf_6690_sensor { 29 struct i2c_client *i2c; 30 struct wf_sensor sens; 31 }; 32 33 #define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) 34 35 static int wf_max6690_get(struct wf_sensor *sr, s32 *value) 36 { 37 struct wf_6690_sensor *max = wf_to_6690(sr); 38 s32 data; 39 40 if (max->i2c == NULL) 41 return -ENODEV; 42 43 /* chip gets initialized by firmware */ 44 data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); 45 if (data < 0) 46 return data; 47 *value = data << 16; 48 return 0; 49 } 50 51 static void wf_max6690_release(struct wf_sensor *sr) 52 { 53 struct wf_6690_sensor *max = wf_to_6690(sr); 54 55 kfree(max); 56 } 57 58 static struct wf_sensor_ops wf_max6690_ops = { 59 .get_value = wf_max6690_get, 60 .release = wf_max6690_release, 61 .owner = THIS_MODULE, 62 }; 63 64 static int wf_max6690_probe(struct i2c_client *client, 65 const struct i2c_device_id *id) 66 { 67 const char *name, *loc; 68 struct wf_6690_sensor *max; 69 int rc; 70 71 loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); 72 if (!loc) { 73 dev_warn(&client->dev, "Missing hwsensor-location property!\n"); 74 return -ENXIO; 75 } 76 77 /* 78 * We only expose the external temperature register for 79 * now as this is all we need for our control loops 80 */ 81 if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT")) 82 name = "backside-temp"; 83 else if (!strcmp(loc, "NB Ambient")) 84 name = "north-bridge-temp"; 85 else if (!strcmp(loc, "GPU Ambient")) 86 name = "gpu-temp"; 87 else 88 return -ENXIO; 89 90 max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); 91 if (max == NULL) { 92 printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " 93 "no memory\n"); 94 return -ENOMEM; 95 } 96 97 max->i2c = client; 98 max->sens.name = (char *)name; /* XXX fix constness in structure */ 99 max->sens.ops = &wf_max6690_ops; 100 i2c_set_clientdata(client, max); 101 102 rc = wf_register_sensor(&max->sens); 103 if (rc) 104 kfree(max); 105 return rc; 106 } 107 108 static int wf_max6690_remove(struct i2c_client *client) 109 { 110 struct wf_6690_sensor *max = i2c_get_clientdata(client); 111 112 max->i2c = NULL; 113 wf_unregister_sensor(&max->sens); 114 115 return 0; 116 } 117 118 static const struct i2c_device_id wf_max6690_id[] = { 119 { "MAC,max6690", 0 }, 120 { } 121 }; 122 MODULE_DEVICE_TABLE(i2c, wf_max6690_id); 123 124 static struct i2c_driver wf_max6690_driver = { 125 .driver = { 126 .name = "wf_max6690", 127 }, 128 .probe = wf_max6690_probe, 129 .remove = wf_max6690_remove, 130 .id_table = wf_max6690_id, 131 }; 132 133 static int __init wf_max6690_sensor_init(void) 134 { 135 return i2c_add_driver(&wf_max6690_driver); 136 } 137 138 static void __exit wf_max6690_sensor_exit(void) 139 { 140 i2c_del_driver(&wf_max6690_driver); 141 } 142 143 module_init(wf_max6690_sensor_init); 144 module_exit(wf_max6690_sensor_exit); 145 146 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); 147 MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control"); 148 MODULE_LICENSE("GPL"); 149