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/delay.h>
0012 #include <linux/slab.h>
0013 #include <linux/init.h>
0014 #include <linux/wait.h>
0015 #include <linux/i2c.h>
0016
0017 #include <asm/machdep.h>
0018 #include <asm/io.h>
0019 #include <asm/sections.h>
0020
0021 #include "windfarm.h"
0022 #include "windfarm_mpu.h"
0023
0024 #define VERSION "1.0"
0025
0026 struct wf_ad7417_priv {
0027 struct kref ref;
0028 struct i2c_client *i2c;
0029 u8 config;
0030 u8 cpu;
0031 const struct mpu_data *mpu;
0032 struct wf_sensor sensors[5];
0033 struct mutex lock;
0034 };
0035
0036 static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
0037 {
0038 struct wf_ad7417_priv *pv = sr->priv;
0039 u8 buf[2];
0040 s16 raw;
0041 int rc;
0042
0043 *value = 0;
0044 mutex_lock(&pv->lock);
0045
0046
0047 buf[0] = 0;
0048 rc = i2c_master_send(pv->i2c, buf, 1);
0049 if (rc < 0)
0050 goto error;
0051 rc = i2c_master_recv(pv->i2c, buf, 2);
0052 if (rc < 0)
0053 goto error;
0054
0055
0056 raw = be16_to_cpup((__le16 *)buf);
0057
0058
0059 *value = ((s32)raw) << 8;
0060
0061 mutex_unlock(&pv->lock);
0062 return 0;
0063
0064 error:
0065 mutex_unlock(&pv->lock);
0066 return -1;
0067 }
0068
0069
0070
0071
0072
0073
0074
0075 #define ADC_12V_CURRENT_SCALE 0x0320
0076 #define ADC_CPU_VOLTAGE_SCALE 0x00a0
0077 #define ADC_CPU_CURRENT_SCALE 0x1f40
0078
0079 static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
0080 int chan, s32 raw, s32 *value)
0081 {
0082 switch(chan) {
0083 case 1:
0084 *value = (raw * (s32)pv->mpu->mdiode +
0085 ((s32)pv->mpu->bdiode << 12)) >> 2;
0086 break;
0087 case 2:
0088 *value = raw * ADC_12V_CURRENT_SCALE;
0089 break;
0090 case 3:
0091 *value = raw * ADC_CPU_VOLTAGE_SCALE;
0092 break;
0093 case 4:
0094 *value = raw * ADC_CPU_CURRENT_SCALE;
0095 break;
0096 }
0097 }
0098
0099 static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
0100 {
0101 struct wf_ad7417_priv *pv = sr->priv;
0102 int chan = sr - pv->sensors;
0103 int i, rc;
0104 u8 buf[2];
0105 u16 raw;
0106
0107 *value = 0;
0108 mutex_lock(&pv->lock);
0109 for (i = 0; i < 10; i++) {
0110
0111 buf[0] = 1;
0112 buf[1] = (pv->config & 0x1f) | (chan << 5);
0113 rc = i2c_master_send(pv->i2c, buf, 2);
0114 if (rc < 0)
0115 goto error;
0116
0117
0118 msleep(1);
0119
0120
0121 buf[0] = 4;
0122 rc = i2c_master_send(pv->i2c, buf, 1);
0123 if (rc < 0)
0124 goto error;
0125
0126
0127 rc = i2c_master_recv(pv->i2c, buf, 2);
0128 if (rc < 0)
0129 goto error;
0130
0131
0132 raw = be16_to_cpup((__le16 *)buf) >> 6;
0133 wf_ad7417_adc_convert(pv, chan, raw, value);
0134
0135 dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
0136 " raw value: 0x%x, conv to: 0x%08x\n",
0137 chan, sr->name, raw, *value);
0138
0139 mutex_unlock(&pv->lock);
0140 return 0;
0141
0142 error:
0143 dev_dbg(&pv->i2c->dev,
0144 "Error reading ADC, try %d...\n", i);
0145 if (i < 9)
0146 msleep(10);
0147 }
0148 mutex_unlock(&pv->lock);
0149 return -1;
0150 }
0151
0152 static void wf_ad7417_release(struct kref *ref)
0153 {
0154 struct wf_ad7417_priv *pv = container_of(ref,
0155 struct wf_ad7417_priv, ref);
0156 kfree(pv);
0157 }
0158
0159 static void wf_ad7417_sensor_release(struct wf_sensor *sr)
0160 {
0161 struct wf_ad7417_priv *pv = sr->priv;
0162
0163 kfree(sr->name);
0164 kref_put(&pv->ref, wf_ad7417_release);
0165 }
0166
0167 static const struct wf_sensor_ops wf_ad7417_temp_ops = {
0168 .get_value = wf_ad7417_temp_get,
0169 .release = wf_ad7417_sensor_release,
0170 .owner = THIS_MODULE,
0171 };
0172
0173 static const struct wf_sensor_ops wf_ad7417_adc_ops = {
0174 .get_value = wf_ad7417_adc_get,
0175 .release = wf_ad7417_sensor_release,
0176 .owner = THIS_MODULE,
0177 };
0178
0179 static void wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
0180 int index, const char *name,
0181 const struct wf_sensor_ops *ops)
0182 {
0183 pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
0184 pv->sensors[index].priv = pv;
0185 pv->sensors[index].ops = ops;
0186 if (!wf_register_sensor(&pv->sensors[index]))
0187 kref_get(&pv->ref);
0188 }
0189
0190 static void wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
0191 {
0192 int rc;
0193 u8 buf[2];
0194 u8 config = 0;
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 buf[0] = 5;
0205 buf[1] = 0;
0206 i2c_master_send(pv->i2c, buf, 2);
0207
0208
0209 buf[0] = 1;
0210 rc = i2c_master_send(pv->i2c, buf, 1);
0211 if (rc > 0) {
0212 rc = i2c_master_recv(pv->i2c, buf, 1);
0213 if (rc > 0) {
0214 config = buf[0];
0215
0216 dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
0217 config);
0218
0219
0220 config &= 0xfe;
0221 buf[0] = 1;
0222 buf[1] = config;
0223 rc = i2c_master_send(pv->i2c, buf, 2);
0224 }
0225 }
0226 if (rc <= 0)
0227 dev_err(&pv->i2c->dev, "Error reading ADC config\n");
0228
0229 pv->config = config;
0230 }
0231
0232 static int wf_ad7417_probe(struct i2c_client *client,
0233 const struct i2c_device_id *id)
0234 {
0235 struct wf_ad7417_priv *pv;
0236 const struct mpu_data *mpu;
0237 const char *loc;
0238 int cpu_nr;
0239
0240 loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
0241 if (!loc) {
0242 dev_warn(&client->dev, "Missing hwsensor-location property!\n");
0243 return -ENXIO;
0244 }
0245
0246
0247
0248
0249
0250 if (!strncmp(loc, "CPU A", 5))
0251 cpu_nr = 0;
0252 else if (!strncmp(loc, "CPU B", 5))
0253 cpu_nr = 1;
0254 else {
0255 pr_err("wf_ad7417: Can't identify location %s\n", loc);
0256 return -ENXIO;
0257 }
0258 mpu = wf_get_mpu(cpu_nr);
0259 if (!mpu) {
0260 dev_err(&client->dev, "Failed to retrieve MPU data\n");
0261 return -ENXIO;
0262 }
0263
0264 pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
0265 if (pv == NULL)
0266 return -ENODEV;
0267
0268 kref_init(&pv->ref);
0269 mutex_init(&pv->lock);
0270 pv->i2c = client;
0271 pv->cpu = cpu_nr;
0272 pv->mpu = mpu;
0273 dev_set_drvdata(&client->dev, pv);
0274
0275
0276 wf_ad7417_init_chip(pv);
0277
0278
0279
0280
0281
0282
0283 wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
0284 wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
0285 wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
0286 wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
0287 wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
0288
0289 return 0;
0290 }
0291
0292 static int wf_ad7417_remove(struct i2c_client *client)
0293 {
0294 struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
0295 int i;
0296
0297
0298 pv->i2c = NULL;
0299
0300
0301 for (i = 0; i < 5; i++)
0302 wf_unregister_sensor(&pv->sensors[i]);
0303
0304 kref_put(&pv->ref, wf_ad7417_release);
0305
0306 return 0;
0307 }
0308
0309 static const struct i2c_device_id wf_ad7417_id[] = {
0310 { "MAC,ad7417", 0 },
0311 { }
0312 };
0313 MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
0314
0315 static const struct of_device_id wf_ad7417_of_id[] = {
0316 { .compatible = "ad7417", },
0317 { }
0318 };
0319 MODULE_DEVICE_TABLE(of, wf_ad7417_of_id);
0320
0321 static struct i2c_driver wf_ad7417_driver = {
0322 .driver = {
0323 .name = "wf_ad7417",
0324 .of_match_table = wf_ad7417_of_id,
0325 },
0326 .probe = wf_ad7417_probe,
0327 .remove = wf_ad7417_remove,
0328 .id_table = wf_ad7417_id,
0329 };
0330
0331 static int wf_ad7417_init(void)
0332 {
0333
0334 if (!of_machine_is_compatible("PowerMac7,2") &&
0335 !of_machine_is_compatible("PowerMac7,3") &&
0336 !of_machine_is_compatible("RackMac3,1"))
0337 return -ENODEV;
0338
0339 return i2c_add_driver(&wf_ad7417_driver);
0340 }
0341
0342 static void wf_ad7417_exit(void)
0343 {
0344 i2c_del_driver(&wf_ad7417_driver);
0345 }
0346
0347 module_init(wf_ad7417_init);
0348 module_exit(wf_ad7417_exit);
0349
0350 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0351 MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
0352 MODULE_LICENSE("GPL");
0353