Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/windfarm: Add ad7417 sensor

For user by the upcoming windfarm_pm72 and windfarm_rm31

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

+347
+347
drivers/macintosh/windfarm_ad7417_sensor.c
··· 1 + /* 2 + * Windfarm PowerMac thermal control. AD7417 sensors 3 + * 4 + * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. 5 + * 6 + * Released under the term of the GNU GPL v2. 7 + */ 8 + 9 + #include <linux/types.h> 10 + #include <linux/errno.h> 11 + #include <linux/kernel.h> 12 + #include <linux/delay.h> 13 + #include <linux/slab.h> 14 + #include <linux/init.h> 15 + #include <linux/wait.h> 16 + #include <linux/i2c.h> 17 + #include <asm/prom.h> 18 + #include <asm/machdep.h> 19 + #include <asm/io.h> 20 + #include <asm/sections.h> 21 + 22 + #include "windfarm.h" 23 + #include "windfarm_mpu.h" 24 + 25 + #define VERSION "1.0" 26 + 27 + struct wf_ad7417_priv { 28 + struct kref ref; 29 + struct i2c_client *i2c; 30 + u8 config; 31 + u8 cpu; 32 + const struct mpu_data *mpu; 33 + struct wf_sensor sensors[5]; 34 + struct mutex lock; 35 + }; 36 + 37 + static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value) 38 + { 39 + struct wf_ad7417_priv *pv = sr->priv; 40 + u8 buf[2]; 41 + s16 raw; 42 + int rc; 43 + 44 + *value = 0; 45 + mutex_lock(&pv->lock); 46 + 47 + /* Read temp register */ 48 + buf[0] = 0; 49 + rc = i2c_master_send(pv->i2c, buf, 1); 50 + if (rc < 0) 51 + goto error; 52 + rc = i2c_master_recv(pv->i2c, buf, 2); 53 + if (rc < 0) 54 + goto error; 55 + 56 + /* Read a a 16-bit signed value */ 57 + raw = be16_to_cpup((__le16 *)buf); 58 + 59 + /* Convert 8.8-bit to 16.16 fixed point */ 60 + *value = ((s32)raw) << 8; 61 + 62 + mutex_unlock(&pv->lock); 63 + return 0; 64 + 65 + error: 66 + mutex_unlock(&pv->lock); 67 + return -1; 68 + } 69 + 70 + /* 71 + * Scaling factors for the AD7417 ADC converters (except 72 + * for the CPU diode which is obtained from the EEPROM). 73 + * Those values are obtained from the property list of 74 + * the darwin driver 75 + */ 76 + #define ADC_12V_CURRENT_SCALE 0x0320 /* _AD2 */ 77 + #define ADC_CPU_VOLTAGE_SCALE 0x00a0 /* _AD3 */ 78 + #define ADC_CPU_CURRENT_SCALE 0x1f40 /* _AD4 */ 79 + 80 + static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv, 81 + int chan, s32 raw, s32 *value) 82 + { 83 + switch(chan) { 84 + case 1: /* Diode */ 85 + *value = (raw * (s32)pv->mpu->mdiode + 86 + ((s32)pv->mpu->bdiode << 12)) >> 2; 87 + break; 88 + case 2: /* 12v current */ 89 + *value = raw * ADC_12V_CURRENT_SCALE; 90 + break; 91 + case 3: /* core voltage */ 92 + *value = raw * ADC_CPU_VOLTAGE_SCALE; 93 + break; 94 + case 4: /* core current */ 95 + *value = raw * ADC_CPU_CURRENT_SCALE; 96 + break; 97 + } 98 + } 99 + 100 + static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value) 101 + { 102 + struct wf_ad7417_priv *pv = sr->priv; 103 + int chan = sr - pv->sensors; 104 + int i, rc; 105 + u8 buf[2]; 106 + u16 raw; 107 + 108 + *value = 0; 109 + mutex_lock(&pv->lock); 110 + for (i = 0; i < 10; i++) { 111 + /* Set channel */ 112 + buf[0] = 1; 113 + buf[1] = (pv->config & 0x1f) | (chan << 5); 114 + rc = i2c_master_send(pv->i2c, buf, 2); 115 + if (rc < 0) 116 + goto error; 117 + 118 + /* Wait for conversion */ 119 + msleep(1); 120 + 121 + /* Switch to data register */ 122 + buf[0] = 4; 123 + rc = i2c_master_send(pv->i2c, buf, 1); 124 + if (rc < 0) 125 + goto error; 126 + 127 + /* Read result */ 128 + rc = i2c_master_recv(pv->i2c, buf, 2); 129 + if (rc < 0) 130 + goto error; 131 + 132 + /* Read a a 16-bit signed value */ 133 + raw = be16_to_cpup((__le16 *)buf) >> 6; 134 + wf_ad7417_adc_convert(pv, chan, raw, value); 135 + 136 + dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]" 137 + " raw value: 0x%x, conv to: 0x%08x\n", 138 + chan, sr->name, raw, *value); 139 + 140 + mutex_unlock(&pv->lock); 141 + return 0; 142 + 143 + error: 144 + dev_dbg(&pv->i2c->dev, 145 + "Error reading ADC, try %d...\n", i); 146 + if (i < 9) 147 + msleep(10); 148 + } 149 + mutex_unlock(&pv->lock); 150 + return -1; 151 + } 152 + 153 + static void wf_ad7417_release(struct kref *ref) 154 + { 155 + struct wf_ad7417_priv *pv = container_of(ref, 156 + struct wf_ad7417_priv, ref); 157 + kfree(pv); 158 + } 159 + 160 + static void wf_ad7417_sensor_release(struct wf_sensor *sr) 161 + { 162 + struct wf_ad7417_priv *pv = sr->priv; 163 + 164 + kfree(sr->name); 165 + kref_put(&pv->ref, wf_ad7417_release); 166 + } 167 + 168 + static const struct wf_sensor_ops wf_ad7417_temp_ops = { 169 + .get_value = wf_ad7417_temp_get, 170 + .release = wf_ad7417_sensor_release, 171 + .owner = THIS_MODULE, 172 + }; 173 + 174 + static const struct wf_sensor_ops wf_ad7417_adc_ops = { 175 + .get_value = wf_ad7417_adc_get, 176 + .release = wf_ad7417_sensor_release, 177 + .owner = THIS_MODULE, 178 + }; 179 + 180 + static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv, 181 + int index, const char *name, 182 + const struct wf_sensor_ops *ops) 183 + { 184 + pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu); 185 + pv->sensors[index].priv = pv; 186 + pv->sensors[index].ops = ops; 187 + if (!wf_register_sensor(&pv->sensors[index])) 188 + kref_get(&pv->ref); 189 + } 190 + 191 + static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv) 192 + { 193 + int rc; 194 + u8 buf[2]; 195 + u8 config = 0; 196 + 197 + /* 198 + * Read ADC the configuration register and cache it. We 199 + * also make sure Config2 contains proper values, I've seen 200 + * cases where we got stale grabage in there, thus preventing 201 + * proper reading of conv. values 202 + */ 203 + 204 + /* Clear Config2 */ 205 + buf[0] = 5; 206 + buf[1] = 0; 207 + i2c_master_send(pv->i2c, buf, 2); 208 + 209 + /* Read & cache Config1 */ 210 + buf[0] = 1; 211 + rc = i2c_master_send(pv->i2c, buf, 1); 212 + if (rc > 0) { 213 + rc = i2c_master_recv(pv->i2c, buf, 1); 214 + if (rc > 0) { 215 + config = buf[0]; 216 + 217 + dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n", 218 + config); 219 + 220 + /* Disable shutdown mode */ 221 + config &= 0xfe; 222 + buf[0] = 1; 223 + buf[1] = config; 224 + rc = i2c_master_send(pv->i2c, buf, 2); 225 + } 226 + } 227 + if (rc <= 0) 228 + dev_err(&pv->i2c->dev, "Error reading ADC config\n"); 229 + 230 + pv->config = config; 231 + } 232 + 233 + static int __devinit wf_ad7417_probe(struct i2c_client *client, 234 + const struct i2c_device_id *id) 235 + { 236 + struct wf_ad7417_priv *pv; 237 + const struct mpu_data *mpu; 238 + const char *loc; 239 + int cpu_nr; 240 + 241 + loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); 242 + if (!loc) { 243 + dev_warn(&client->dev, "Missing hwsensor-location property!\n"); 244 + return -ENXIO; 245 + } 246 + 247 + /* 248 + * Identify which CPU we belong to by looking at the first entry 249 + * in the hwsensor-location list 250 + */ 251 + if (!strncmp(loc, "CPU A", 5)) 252 + cpu_nr = 0; 253 + else if (!strncmp(loc, "CPU B", 5)) 254 + cpu_nr = 1; 255 + else { 256 + pr_err("wf_ad7417: Can't identify location %s\n", loc); 257 + return -ENXIO; 258 + } 259 + mpu = wf_get_mpu(cpu_nr); 260 + if (!mpu) { 261 + dev_err(&client->dev, "Failed to retrieve MPU data\n"); 262 + return -ENXIO; 263 + } 264 + 265 + pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL); 266 + if (pv == NULL) 267 + return -ENODEV; 268 + 269 + kref_init(&pv->ref); 270 + mutex_init(&pv->lock); 271 + pv->i2c = client; 272 + pv->cpu = cpu_nr; 273 + pv->mpu = mpu; 274 + dev_set_drvdata(&client->dev, pv); 275 + 276 + /* Initialize the chip */ 277 + wf_ad7417_init_chip(pv); 278 + 279 + /* 280 + * We cannot rely on Apple device-tree giving us child 281 + * node with the names of the individual sensors so we 282 + * just hard code what we know about them 283 + */ 284 + wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops); 285 + wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops); 286 + wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops); 287 + wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops); 288 + wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops); 289 + 290 + return 0; 291 + } 292 + 293 + static int __devexit wf_ad7417_remove(struct i2c_client *client) 294 + { 295 + struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev); 296 + int i; 297 + 298 + /* Mark client detached */ 299 + pv->i2c = NULL; 300 + 301 + /* Release sensor */ 302 + for (i = 0; i < 5; i++) 303 + wf_unregister_sensor(&pv->sensors[i]); 304 + 305 + kref_put(&pv->ref, wf_ad7417_release); 306 + 307 + return 0; 308 + } 309 + 310 + static const struct i2c_device_id wf_ad7417_id[] = { 311 + { "MAC,ad7417", 0 }, 312 + { } 313 + }; 314 + MODULE_DEVICE_TABLE(i2c, wf_ad7417_id); 315 + 316 + static struct i2c_driver wf_ad7417_driver = { 317 + .driver = { 318 + .name = "wf_ad7417", 319 + }, 320 + .probe = wf_ad7417_probe, 321 + .remove = wf_ad7417_remove, 322 + .id_table = wf_ad7417_id, 323 + }; 324 + 325 + static int __devinit wf_ad7417_init(void) 326 + { 327 + /* This is only supported on these machines */ 328 + if (!of_machine_is_compatible("PowerMac7,2") && 329 + !of_machine_is_compatible("PowerMac7,3") && 330 + !of_machine_is_compatible("RackMac3,1")) 331 + return -ENODEV; 332 + 333 + return i2c_add_driver(&wf_ad7417_driver); 334 + } 335 + 336 + static void __devexit wf_ad7417_exit(void) 337 + { 338 + i2c_del_driver(&wf_ad7417_driver); 339 + } 340 + 341 + module_init(wf_ad7417_init); 342 + module_exit(wf_ad7417_exit); 343 + 344 + MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 345 + MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs"); 346 + MODULE_LICENSE("GPL"); 347 +