Commit | Line | Data |
---|---|---|
2c162f9b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
75722d39 BH |
2 | /* |
3 | * Windfarm PowerMac thermal control. LM75 sensor | |
4 | * | |
5 | * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. | |
6 | * <benh@kernel.crashing.org> | |
75722d39 BH |
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> | |
bcf3588d | 17 | #include <linux/of_device.h> |
75722d39 BH |
18 | #include <asm/machdep.h> |
19 | #include <asm/io.h> | |
75722d39 | 20 | #include <asm/sections.h> |
a28d3af2 | 21 | #include <asm/pmac_low_i2c.h> |
75722d39 BH |
22 | |
23 | #include "windfarm.h" | |
24 | ||
5400480f | 25 | #define VERSION "1.0" |
75722d39 BH |
26 | |
27 | #undef DEBUG | |
28 | ||
29 | #ifdef DEBUG | |
30 | #define DBG(args...) printk(args) | |
31 | #else | |
32 | #define DBG(args...) do { } while(0) | |
33 | #endif | |
34 | ||
35 | struct wf_lm75_sensor { | |
36 | int ds1775 : 1; | |
37 | int inited : 1; | |
5400480f BH |
38 | struct i2c_client *i2c; |
39 | struct wf_sensor sens; | |
75722d39 BH |
40 | }; |
41 | #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) | |
75722d39 BH |
42 | |
43 | static int wf_lm75_get(struct wf_sensor *sr, s32 *value) | |
44 | { | |
45 | struct wf_lm75_sensor *lm = wf_to_lm75(sr); | |
46 | s32 data; | |
47 | ||
351ca3e3 | 48 | if (lm->i2c == NULL) |
75722d39 BH |
49 | return -ENODEV; |
50 | ||
51 | /* Init chip if necessary */ | |
52 | if (!lm->inited) { | |
351ca3e3 | 53 | u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1); |
75722d39 BH |
54 | |
55 | DBG("wf_lm75: Initializing %s, cfg was: %02x\n", | |
56 | sr->name, cfg); | |
57 | ||
58 | /* clear shutdown bit, keep other settings as left by | |
59 | * the firmware for now | |
60 | */ | |
61 | cfg_new = cfg & ~0x01; | |
351ca3e3 | 62 | i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new); |
75722d39 BH |
63 | lm->inited = 1; |
64 | ||
65 | /* If we just powered it up, let's wait 200 ms */ | |
66 | msleep(200); | |
67 | } | |
68 | ||
69 | /* Read temperature register */ | |
351ca3e3 | 70 | data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0)); |
75722d39 BH |
71 | data <<= 8; |
72 | *value = data; | |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
77 | static void wf_lm75_release(struct wf_sensor *sr) | |
78 | { | |
79 | struct wf_lm75_sensor *lm = wf_to_lm75(sr); | |
80 | ||
75722d39 BH |
81 | kfree(lm); |
82 | } | |
83 | ||
de854e54 | 84 | static const struct wf_sensor_ops wf_lm75_ops = { |
75722d39 BH |
85 | .get_value = wf_lm75_get, |
86 | .release = wf_lm75_release, | |
87 | .owner = THIS_MODULE, | |
88 | }; | |
89 | ||
51a9e175 UKK |
90 | static int wf_lm75_probe(struct i2c_client *client) |
91 | { | |
92 | const struct i2c_device_id *id = i2c_client_get_device_id(client); | |
75722d39 | 93 | struct wf_lm75_sensor *lm; |
bcf3588d | 94 | int rc, ds1775; |
5400480f | 95 | const char *name, *loc; |
351ca3e3 | 96 | |
bcf3588d WS |
97 | if (id) |
98 | ds1775 = id->driver_data; | |
99 | else | |
100 | ds1775 = !!of_device_get_match_data(&client->dev); | |
101 | ||
351ca3e3 | 102 | DBG("wf_lm75: creating %s device at address 0x%02x\n", |
5400480f BH |
103 | ds1775 ? "ds1775" : "lm75", client->addr); |
104 | ||
105 | loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); | |
106 | if (!loc) { | |
107 | dev_warn(&client->dev, "Missing hwsensor-location property!\n"); | |
108 | return -ENXIO; | |
109 | } | |
75722d39 BH |
110 | |
111 | /* Usual rant about sensor names not beeing very consistent in | |
112 | * the device-tree, oh well ... | |
113 | * Add more entries below as you deal with more setups | |
114 | */ | |
115 | if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) | |
351ca3e3 | 116 | name = "hd-temp"; |
80ff974d | 117 | else if (!strcmp(loc, "Incoming Air Temp")) |
351ca3e3 | 118 | name = "incoming-air-temp"; |
80ff974d | 119 | else if (!strcmp(loc, "ODD Temp")) |
351ca3e3 | 120 | name = "optical-drive-temp"; |
80ff974d | 121 | else if (!strcmp(loc, "HD Temp")) |
351ca3e3 | 122 | name = "hard-drive-temp"; |
d839ba2a BH |
123 | else if (!strcmp(loc, "PCI SLOTS")) |
124 | name = "slots-temp"; | |
125 | else if (!strcmp(loc, "CPU A INLET")) | |
126 | name = "cpu-inlet-temp-0"; | |
127 | else if (!strcmp(loc, "CPU B INLET")) | |
128 | name = "cpu-inlet-temp-1"; | |
75722d39 | 129 | else |
5400480f BH |
130 | return -ENXIO; |
131 | ||
75722d39 | 132 | |
5400480f BH |
133 | lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); |
134 | if (lm == NULL) | |
a28d3af2 | 135 | return -ENODEV; |
75722d39 | 136 | |
5400480f BH |
137 | lm->inited = 0; |
138 | lm->ds1775 = ds1775; | |
139 | lm->i2c = client; | |
8bb61fe1 | 140 | lm->sens.name = name; |
5400480f BH |
141 | lm->sens.ops = &wf_lm75_ops; |
142 | i2c_set_clientdata(client, lm); | |
b55fafc5 | 143 | |
5400480f BH |
144 | rc = wf_register_sensor(&lm->sens); |
145 | if (rc) | |
146 | kfree(lm); | |
147 | return rc; | |
75722d39 BH |
148 | } |
149 | ||
ed5c2f5f | 150 | static void wf_lm75_remove(struct i2c_client *client) |
75722d39 | 151 | { |
351ca3e3 | 152 | struct wf_lm75_sensor *lm = i2c_get_clientdata(client); |
75722d39 | 153 | |
75722d39 | 154 | /* Mark client detached */ |
351ca3e3 | 155 | lm->i2c = NULL; |
75722d39 BH |
156 | |
157 | /* release sensor */ | |
158 | wf_unregister_sensor(&lm->sens); | |
75722d39 BH |
159 | } |
160 | ||
351ca3e3 | 161 | static const struct i2c_device_id wf_lm75_id[] = { |
5400480f BH |
162 | { "MAC,lm75", 0 }, |
163 | { "MAC,ds1775", 1 }, | |
351ca3e3 JD |
164 | { } |
165 | }; | |
5400480f | 166 | MODULE_DEVICE_TABLE(i2c, wf_lm75_id); |
351ca3e3 | 167 | |
bcf3588d WS |
168 | static const struct of_device_id wf_lm75_of_id[] = { |
169 | { .compatible = "lm75", .data = (void *)0}, | |
170 | { .compatible = "ds1775", .data = (void *)1 }, | |
171 | { } | |
172 | }; | |
173 | MODULE_DEVICE_TABLE(of, wf_lm75_of_id); | |
174 | ||
351ca3e3 JD |
175 | static struct i2c_driver wf_lm75_driver = { |
176 | .driver = { | |
177 | .name = "wf_lm75", | |
bcf3588d | 178 | .of_match_table = wf_lm75_of_id, |
351ca3e3 | 179 | }, |
51a9e175 | 180 | .probe_new = wf_lm75_probe, |
351ca3e3 JD |
181 | .remove = wf_lm75_remove, |
182 | .id_table = wf_lm75_id, | |
183 | }; | |
184 | ||
f7fb862b | 185 | module_i2c_driver(wf_lm75_driver); |
75722d39 BH |
186 | |
187 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | |
188 | MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); | |
189 | MODULE_LICENSE("GPL"); | |
190 |