1 /* 2 * Windfarm PowerMac thermal control. LM75 sensor 3 * 4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. 5 * <benh@kernel.crashing.org> 6 * 7 * Released under the term of the GNU GPL v2. 8 */ 9 10 #include <linux/types.h> 11 #include <linux/errno.h> 12 #include <linux/kernel.h> 13 #include <linux/delay.h> 14 #include <linux/slab.h> 15 #include <linux/init.h> 16 #include <linux/wait.h> 17 #include <linux/i2c.h> 18 #include <linux/i2c-dev.h> 19 #include <asm/prom.h> 20 #include <asm/machdep.h> 21 #include <asm/io.h> 22 #include <asm/system.h> 23 #include <asm/sections.h> 24 25 #include "windfarm.h" 26 27 #define VERSION "0.1" 28 29 #undef DEBUG 30 31 #ifdef DEBUG 32 #define DBG(args...) printk(args) 33 #else 34 #define DBG(args...) do { } while(0) 35 #endif 36 37 struct wf_lm75_sensor { 38 int ds1775 : 1; 39 int inited : 1; 40 struct i2c_client i2c; 41 struct wf_sensor sens; 42 }; 43 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) 44 #define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c) 45 46 static int wf_lm75_attach(struct i2c_adapter *adapter); 47 static int wf_lm75_detach(struct i2c_client *client); 48 49 static struct i2c_driver wf_lm75_driver = { 50 .owner = THIS_MODULE, 51 .name = "wf_lm75", 52 .flags = I2C_DF_NOTIFY, 53 .attach_adapter = wf_lm75_attach, 54 .detach_client = wf_lm75_detach, 55 }; 56 57 static int wf_lm75_get(struct wf_sensor *sr, s32 *value) 58 { 59 struct wf_lm75_sensor *lm = wf_to_lm75(sr); 60 s32 data; 61 62 if (lm->i2c.adapter == NULL) 63 return -ENODEV; 64 65 /* Init chip if necessary */ 66 if (!lm->inited) { 67 u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1); 68 69 DBG("wf_lm75: Initializing %s, cfg was: %02x\n", 70 sr->name, cfg); 71 72 /* clear shutdown bit, keep other settings as left by 73 * the firmware for now 74 */ 75 cfg_new = cfg & ~0x01; 76 i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new); 77 lm->inited = 1; 78 79 /* If we just powered it up, let's wait 200 ms */ 80 msleep(200); 81 } 82 83 /* Read temperature register */ 84 data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0)); 85 data <<= 8; 86 *value = data; 87 88 return 0; 89 } 90 91 static void wf_lm75_release(struct wf_sensor *sr) 92 { 93 struct wf_lm75_sensor *lm = wf_to_lm75(sr); 94 95 /* check if client is registered and detach from i2c */ 96 if (lm->i2c.adapter) { 97 i2c_detach_client(&lm->i2c); 98 lm->i2c.adapter = NULL; 99 } 100 101 kfree(lm); 102 } 103 104 static struct wf_sensor_ops wf_lm75_ops = { 105 .get_value = wf_lm75_get, 106 .release = wf_lm75_release, 107 .owner = THIS_MODULE, 108 }; 109 110 static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, 111 u8 addr, int ds1775, 112 const char *loc) 113 { 114 struct wf_lm75_sensor *lm; 115 116 DBG("wf_lm75: creating %s device at address 0x%02x\n", 117 ds1775 ? "ds1775" : "lm75", addr); 118 119 lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); 120 if (lm == NULL) 121 return NULL; 122 memset(lm, 0, sizeof(struct wf_lm75_sensor)); 123 124 /* Usual rant about sensor names not beeing very consistent in 125 * the device-tree, oh well ... 126 * Add more entries below as you deal with more setups 127 */ 128 if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) 129 lm->sens.name = "hd-temp"; 130 else 131 goto fail; 132 133 lm->inited = 0; 134 lm->sens.ops = &wf_lm75_ops; 135 lm->ds1775 = ds1775; 136 lm->i2c.addr = (addr >> 1) & 0x7f; 137 lm->i2c.adapter = adapter; 138 lm->i2c.driver = &wf_lm75_driver; 139 strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1); 140 141 if (i2c_attach_client(&lm->i2c)) { 142 printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", 143 ds1775 ? "ds1775" : "lm75", lm->i2c.name); 144 goto fail; 145 } 146 147 if (wf_register_sensor(&lm->sens)) { 148 i2c_detach_client(&lm->i2c); 149 goto fail; 150 } 151 152 return lm; 153 fail: 154 kfree(lm); 155 return NULL; 156 } 157 158 static int wf_lm75_attach(struct i2c_adapter *adapter) 159 { 160 u8 bus_id; 161 struct device_node *smu, *bus, *dev; 162 163 /* We currently only deal with LM75's hanging off the SMU 164 * i2c busses. If we extend that driver to other/older 165 * machines, we should split this function into SMU-i2c, 166 * keywest-i2c, PMU-i2c, ... 167 */ 168 169 DBG("wf_lm75: adapter %s detected\n", adapter->name); 170 171 if (strncmp(adapter->name, "smu-i2c-", 8) != 0) 172 return 0; 173 smu = of_find_node_by_type(NULL, "smu"); 174 if (smu == NULL) 175 return 0; 176 177 /* Look for the bus in the device-tree */ 178 bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16); 179 180 DBG("wf_lm75: bus ID is %x\n", bus_id); 181 182 /* Look for sensors subdir */ 183 for (bus = NULL; 184 (bus = of_get_next_child(smu, bus)) != NULL;) { 185 u32 *reg; 186 187 if (strcmp(bus->name, "i2c")) 188 continue; 189 reg = (u32 *)get_property(bus, "reg", NULL); 190 if (reg == NULL) 191 continue; 192 if (bus_id == *reg) 193 break; 194 } 195 of_node_put(smu); 196 if (bus == NULL) { 197 printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found" 198 " in device-tree !\n", bus_id); 199 return 0; 200 } 201 202 DBG("wf_lm75: bus found, looking for device...\n"); 203 204 /* Now look for lm75(s) in there */ 205 for (dev = NULL; 206 (dev = of_get_next_child(bus, dev)) != NULL;) { 207 const char *loc = 208 get_property(dev, "hwsensor-location", NULL); 209 u32 *reg = (u32 *)get_property(dev, "reg", NULL); 210 DBG(" dev: %s... (loc: %p, reg: %p)\n", dev->name, loc, reg); 211 if (loc == NULL || reg == NULL) 212 continue; 213 /* real lm75 */ 214 if (device_is_compatible(dev, "lm75")) 215 wf_lm75_create(adapter, *reg, 0, loc); 216 /* ds1775 (compatible, better resolution */ 217 else if (device_is_compatible(dev, "ds1775")) 218 wf_lm75_create(adapter, *reg, 1, loc); 219 } 220 221 of_node_put(bus); 222 223 return 0; 224 } 225 226 static int wf_lm75_detach(struct i2c_client *client) 227 { 228 struct wf_lm75_sensor *lm = i2c_to_lm75(client); 229 230 DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); 231 232 /* Mark client detached */ 233 lm->i2c.adapter = NULL; 234 235 /* release sensor */ 236 wf_unregister_sensor(&lm->sens); 237 238 return 0; 239 } 240 241 static int __init wf_lm75_sensor_init(void) 242 { 243 int rc; 244 245 rc = i2c_add_driver(&wf_lm75_driver); 246 if (rc < 0) 247 return rc; 248 return 0; 249 } 250 251 static void __exit wf_lm75_sensor_exit(void) 252 { 253 i2c_del_driver(&wf_lm75_driver); 254 } 255 256 257 module_init(wf_lm75_sensor_init); 258 module_exit(wf_lm75_sensor_exit); 259 260 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 261 MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); 262 MODULE_LICENSE("GPL"); 263 264