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 #include <asm/pmac_low_i2c.h>
0021
0022 #include "windfarm.h"
0023
0024 #define VERSION "1.0"
0025
0026 #undef DEBUG
0027
0028 #ifdef DEBUG
0029 #define DBG(args...) printk(args)
0030 #else
0031 #define DBG(args...) do { } while(0)
0032 #endif
0033
0034 struct wf_lm87_sensor {
0035 struct i2c_client *i2c;
0036 struct wf_sensor sens;
0037 };
0038 #define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
0039
0040
0041 static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
0042 {
0043 int rc, tries = 0;
0044 u8 buf;
0045
0046 for (;;) {
0047
0048 buf = (u8)reg;
0049 rc = i2c_master_send(chip, &buf, 1);
0050 if (rc <= 0)
0051 goto error;
0052 rc = i2c_master_recv(chip, &buf, 1);
0053 if (rc <= 0)
0054 goto error;
0055 return (int)buf;
0056 error:
0057 DBG("wf_lm87: Error reading LM87, retrying...\n");
0058 if (++tries > 10) {
0059 printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
0060 return -EIO;
0061 }
0062 msleep(10);
0063 }
0064 }
0065
0066 static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
0067 {
0068 struct wf_lm87_sensor *lm = sr->priv;
0069 s32 temp;
0070
0071 if (lm->i2c == NULL)
0072 return -ENODEV;
0073
0074 #define LM87_INT_TEMP 0x27
0075
0076
0077 temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
0078 if (temp < 0)
0079 return temp;
0080 *value = temp << 16;
0081
0082 return 0;
0083 }
0084
0085 static void wf_lm87_release(struct wf_sensor *sr)
0086 {
0087 struct wf_lm87_sensor *lm = wf_to_lm87(sr);
0088
0089 kfree(lm);
0090 }
0091
0092 static const struct wf_sensor_ops wf_lm87_ops = {
0093 .get_value = wf_lm87_get,
0094 .release = wf_lm87_release,
0095 .owner = THIS_MODULE,
0096 };
0097
0098 static int wf_lm87_probe(struct i2c_client *client,
0099 const struct i2c_device_id *id)
0100 {
0101 struct wf_lm87_sensor *lm;
0102 const char *name = NULL, *loc;
0103 struct device_node *np = NULL;
0104 int rc;
0105
0106
0107
0108
0109
0110
0111 for_each_child_of_node(client->dev.of_node, np) {
0112 if (!of_node_name_eq(np, "int-temp"))
0113 continue;
0114 loc = of_get_property(np, "location", NULL);
0115 if (!loc)
0116 continue;
0117 if (strstr(loc, "DIMM"))
0118 name = "dimms-temp";
0119 else if (strstr(loc, "Processors"))
0120 name = "between-cpus-temp";
0121 if (name) {
0122 of_node_put(np);
0123 break;
0124 }
0125 }
0126 if (!name) {
0127 pr_warn("wf_lm87: Unsupported sensor %pOF\n",
0128 client->dev.of_node);
0129 return -ENODEV;
0130 }
0131
0132 lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
0133 if (lm == NULL)
0134 return -ENODEV;
0135
0136 lm->i2c = client;
0137 lm->sens.name = name;
0138 lm->sens.ops = &wf_lm87_ops;
0139 lm->sens.priv = lm;
0140 i2c_set_clientdata(client, lm);
0141
0142 rc = wf_register_sensor(&lm->sens);
0143 if (rc)
0144 kfree(lm);
0145 return rc;
0146 }
0147
0148 static int wf_lm87_remove(struct i2c_client *client)
0149 {
0150 struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
0151
0152
0153 lm->i2c = NULL;
0154
0155
0156 wf_unregister_sensor(&lm->sens);
0157
0158 return 0;
0159 }
0160
0161 static const struct i2c_device_id wf_lm87_id[] = {
0162 { "MAC,lm87cimt", 0 },
0163 { }
0164 };
0165 MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
0166
0167 static const struct of_device_id wf_lm87_of_id[] = {
0168 { .compatible = "lm87cimt", },
0169 { }
0170 };
0171 MODULE_DEVICE_TABLE(of, wf_lm87_of_id);
0172
0173 static struct i2c_driver wf_lm87_driver = {
0174 .driver = {
0175 .name = "wf_lm87",
0176 .of_match_table = wf_lm87_of_id,
0177 },
0178 .probe = wf_lm87_probe,
0179 .remove = wf_lm87_remove,
0180 .id_table = wf_lm87_id,
0181 };
0182
0183 static int __init wf_lm87_sensor_init(void)
0184 {
0185
0186 if (!of_machine_is_compatible("RackMac3,1"))
0187 return -ENODEV;
0188
0189 return i2c_add_driver(&wf_lm87_driver);
0190 }
0191
0192 static void __exit wf_lm87_sensor_exit(void)
0193 {
0194 i2c_del_driver(&wf_lm87_driver);
0195 }
0196
0197
0198 module_init(wf_lm87_sensor_init);
0199 module_exit(wf_lm87_sensor_exit);
0200
0201 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0202 MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
0203 MODULE_LICENSE("GPL");
0204