12c162f9bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
275722d39SBenjamin Herrenschmidt /*
375722d39SBenjamin Herrenschmidt * Windfarm PowerMac thermal control. LM75 sensor
475722d39SBenjamin Herrenschmidt *
575722d39SBenjamin Herrenschmidt * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
675722d39SBenjamin Herrenschmidt * <benh@kernel.crashing.org>
775722d39SBenjamin Herrenschmidt */
875722d39SBenjamin Herrenschmidt
975722d39SBenjamin Herrenschmidt #include <linux/types.h>
1075722d39SBenjamin Herrenschmidt #include <linux/errno.h>
1175722d39SBenjamin Herrenschmidt #include <linux/kernel.h>
1275722d39SBenjamin Herrenschmidt #include <linux/delay.h>
1375722d39SBenjamin Herrenschmidt #include <linux/slab.h>
1475722d39SBenjamin Herrenschmidt #include <linux/init.h>
1575722d39SBenjamin Herrenschmidt #include <linux/wait.h>
1675722d39SBenjamin Herrenschmidt #include <linux/i2c.h>
17233d687dSRob Herring #include <linux/of.h>
1875722d39SBenjamin Herrenschmidt #include <asm/machdep.h>
1975722d39SBenjamin Herrenschmidt #include <asm/io.h>
2075722d39SBenjamin Herrenschmidt #include <asm/sections.h>
21a28d3af2SBenjamin Herrenschmidt #include <asm/pmac_low_i2c.h>
2275722d39SBenjamin Herrenschmidt
2375722d39SBenjamin Herrenschmidt #include "windfarm.h"
2475722d39SBenjamin Herrenschmidt
255400480fSBenjamin Herrenschmidt #define VERSION "1.0"
2675722d39SBenjamin Herrenschmidt
2775722d39SBenjamin Herrenschmidt #undef DEBUG
2875722d39SBenjamin Herrenschmidt
2975722d39SBenjamin Herrenschmidt #ifdef DEBUG
3075722d39SBenjamin Herrenschmidt #define DBG(args...) printk(args)
3175722d39SBenjamin Herrenschmidt #else
3275722d39SBenjamin Herrenschmidt #define DBG(args...) do { } while(0)
3375722d39SBenjamin Herrenschmidt #endif
3475722d39SBenjamin Herrenschmidt
3575722d39SBenjamin Herrenschmidt struct wf_lm75_sensor {
36748ea32dSNathan Chancellor unsigned int ds1775 : 1;
37748ea32dSNathan Chancellor unsigned int inited : 1;
38351ca3e3SJean Delvare struct i2c_client *i2c;
3975722d39SBenjamin Herrenschmidt struct wf_sensor sens;
4075722d39SBenjamin Herrenschmidt };
4175722d39SBenjamin Herrenschmidt #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
4275722d39SBenjamin Herrenschmidt
wf_lm75_get(struct wf_sensor * sr,s32 * value)4375722d39SBenjamin Herrenschmidt static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
4475722d39SBenjamin Herrenschmidt {
4575722d39SBenjamin Herrenschmidt struct wf_lm75_sensor *lm = wf_to_lm75(sr);
4675722d39SBenjamin Herrenschmidt s32 data;
4775722d39SBenjamin Herrenschmidt
48351ca3e3SJean Delvare if (lm->i2c == NULL)
4975722d39SBenjamin Herrenschmidt return -ENODEV;
5075722d39SBenjamin Herrenschmidt
5175722d39SBenjamin Herrenschmidt /* Init chip if necessary */
5275722d39SBenjamin Herrenschmidt if (!lm->inited) {
53351ca3e3SJean Delvare u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1);
5475722d39SBenjamin Herrenschmidt
5575722d39SBenjamin Herrenschmidt DBG("wf_lm75: Initializing %s, cfg was: %02x\n",
5675722d39SBenjamin Herrenschmidt sr->name, cfg);
5775722d39SBenjamin Herrenschmidt
5875722d39SBenjamin Herrenschmidt /* clear shutdown bit, keep other settings as left by
5975722d39SBenjamin Herrenschmidt * the firmware for now
6075722d39SBenjamin Herrenschmidt */
6175722d39SBenjamin Herrenschmidt cfg_new = cfg & ~0x01;
62351ca3e3SJean Delvare i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new);
6375722d39SBenjamin Herrenschmidt lm->inited = 1;
6475722d39SBenjamin Herrenschmidt
6575722d39SBenjamin Herrenschmidt /* If we just powered it up, let's wait 200 ms */
6675722d39SBenjamin Herrenschmidt msleep(200);
6775722d39SBenjamin Herrenschmidt }
6875722d39SBenjamin Herrenschmidt
6975722d39SBenjamin Herrenschmidt /* Read temperature register */
70351ca3e3SJean Delvare data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0));
7175722d39SBenjamin Herrenschmidt data <<= 8;
7275722d39SBenjamin Herrenschmidt *value = data;
7375722d39SBenjamin Herrenschmidt
7475722d39SBenjamin Herrenschmidt return 0;
7575722d39SBenjamin Herrenschmidt }
7675722d39SBenjamin Herrenschmidt
wf_lm75_release(struct wf_sensor * sr)7775722d39SBenjamin Herrenschmidt static void wf_lm75_release(struct wf_sensor *sr)
7875722d39SBenjamin Herrenschmidt {
7975722d39SBenjamin Herrenschmidt struct wf_lm75_sensor *lm = wf_to_lm75(sr);
8075722d39SBenjamin Herrenschmidt
8175722d39SBenjamin Herrenschmidt kfree(lm);
8275722d39SBenjamin Herrenschmidt }
8375722d39SBenjamin Herrenschmidt
84de854e54SJulia Lawall static const struct wf_sensor_ops wf_lm75_ops = {
8575722d39SBenjamin Herrenschmidt .get_value = wf_lm75_get,
8675722d39SBenjamin Herrenschmidt .release = wf_lm75_release,
8775722d39SBenjamin Herrenschmidt .owner = THIS_MODULE,
8875722d39SBenjamin Herrenschmidt };
8975722d39SBenjamin Herrenschmidt
wf_lm75_probe(struct i2c_client * client)9051a9e175SUwe Kleine-König static int wf_lm75_probe(struct i2c_client *client)
9175722d39SBenjamin Herrenschmidt {
9251a9e175SUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client);
9375722d39SBenjamin Herrenschmidt struct wf_lm75_sensor *lm;
94bcf3588dSWolfram Sang int rc, ds1775;
955400480fSBenjamin Herrenschmidt const char *name, *loc;
96351ca3e3SJean Delvare
97bcf3588dSWolfram Sang if (id)
98bcf3588dSWolfram Sang ds1775 = id->driver_data;
99bcf3588dSWolfram Sang else
100bcf3588dSWolfram Sang ds1775 = !!of_device_get_match_data(&client->dev);
101bcf3588dSWolfram Sang
102351ca3e3SJean Delvare DBG("wf_lm75: creating %s device at address 0x%02x\n",
1035400480fSBenjamin Herrenschmidt ds1775 ? "ds1775" : "lm75", client->addr);
1045400480fSBenjamin Herrenschmidt
1055400480fSBenjamin Herrenschmidt loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
1065400480fSBenjamin Herrenschmidt if (!loc) {
1075400480fSBenjamin Herrenschmidt dev_warn(&client->dev, "Missing hwsensor-location property!\n");
1085400480fSBenjamin Herrenschmidt return -ENXIO;
1095400480fSBenjamin Herrenschmidt }
11075722d39SBenjamin Herrenschmidt
11175722d39SBenjamin Herrenschmidt /* Usual rant about sensor names not beeing very consistent in
11275722d39SBenjamin Herrenschmidt * the device-tree, oh well ...
11375722d39SBenjamin Herrenschmidt * Add more entries below as you deal with more setups
11475722d39SBenjamin Herrenschmidt */
11575722d39SBenjamin Herrenschmidt if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
116351ca3e3SJean Delvare name = "hd-temp";
11780ff974dSÉtienne Bersac else if (!strcmp(loc, "Incoming Air Temp"))
118351ca3e3SJean Delvare name = "incoming-air-temp";
11980ff974dSÉtienne Bersac else if (!strcmp(loc, "ODD Temp"))
120351ca3e3SJean Delvare name = "optical-drive-temp";
12180ff974dSÉtienne Bersac else if (!strcmp(loc, "HD Temp"))
122351ca3e3SJean Delvare name = "hard-drive-temp";
123d839ba2aSBenjamin Herrenschmidt else if (!strcmp(loc, "PCI SLOTS"))
124d839ba2aSBenjamin Herrenschmidt name = "slots-temp";
125d839ba2aSBenjamin Herrenschmidt else if (!strcmp(loc, "CPU A INLET"))
126d839ba2aSBenjamin Herrenschmidt name = "cpu-inlet-temp-0";
127d839ba2aSBenjamin Herrenschmidt else if (!strcmp(loc, "CPU B INLET"))
128d839ba2aSBenjamin Herrenschmidt name = "cpu-inlet-temp-1";
12975722d39SBenjamin Herrenschmidt else
1305400480fSBenjamin Herrenschmidt return -ENXIO;
13175722d39SBenjamin Herrenschmidt
13275722d39SBenjamin Herrenschmidt
1335400480fSBenjamin Herrenschmidt lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
1345400480fSBenjamin Herrenschmidt if (lm == NULL)
135a28d3af2SBenjamin Herrenschmidt return -ENODEV;
13675722d39SBenjamin Herrenschmidt
1375400480fSBenjamin Herrenschmidt lm->inited = 0;
1385400480fSBenjamin Herrenschmidt lm->ds1775 = ds1775;
1395400480fSBenjamin Herrenschmidt lm->i2c = client;
1408bb61fe1SGeert Uytterhoeven lm->sens.name = name;
1415400480fSBenjamin Herrenschmidt lm->sens.ops = &wf_lm75_ops;
1425400480fSBenjamin Herrenschmidt i2c_set_clientdata(client, lm);
14375722d39SBenjamin Herrenschmidt
1445400480fSBenjamin Herrenschmidt rc = wf_register_sensor(&lm->sens);
1455400480fSBenjamin Herrenschmidt if (rc)
1465400480fSBenjamin Herrenschmidt kfree(lm);
1475400480fSBenjamin Herrenschmidt return rc;
14875722d39SBenjamin Herrenschmidt }
14975722d39SBenjamin Herrenschmidt
wf_lm75_remove(struct i2c_client * client)150ed5c2f5fSUwe Kleine-König static void wf_lm75_remove(struct i2c_client *client)
15175722d39SBenjamin Herrenschmidt {
152351ca3e3SJean Delvare struct wf_lm75_sensor *lm = i2c_get_clientdata(client);
15375722d39SBenjamin Herrenschmidt
15475722d39SBenjamin Herrenschmidt /* Mark client detached */
155351ca3e3SJean Delvare lm->i2c = NULL;
15675722d39SBenjamin Herrenschmidt
15775722d39SBenjamin Herrenschmidt /* release sensor */
15875722d39SBenjamin Herrenschmidt wf_unregister_sensor(&lm->sens);
15975722d39SBenjamin Herrenschmidt }
16075722d39SBenjamin Herrenschmidt
161351ca3e3SJean Delvare static const struct i2c_device_id wf_lm75_id[] = {
1625400480fSBenjamin Herrenschmidt { "MAC,lm75", 0 },
1635400480fSBenjamin Herrenschmidt { "MAC,ds1775", 1 },
164351ca3e3SJean Delvare { }
165351ca3e3SJean Delvare };
1665400480fSBenjamin Herrenschmidt MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
167351ca3e3SJean Delvare
168bcf3588dSWolfram Sang static const struct of_device_id wf_lm75_of_id[] = {
169bcf3588dSWolfram Sang { .compatible = "lm75", .data = (void *)0},
170bcf3588dSWolfram Sang { .compatible = "ds1775", .data = (void *)1 },
171bcf3588dSWolfram Sang { }
172bcf3588dSWolfram Sang };
173bcf3588dSWolfram Sang MODULE_DEVICE_TABLE(of, wf_lm75_of_id);
174bcf3588dSWolfram Sang
175351ca3e3SJean Delvare static struct i2c_driver wf_lm75_driver = {
176351ca3e3SJean Delvare .driver = {
177351ca3e3SJean Delvare .name = "wf_lm75",
178bcf3588dSWolfram Sang .of_match_table = wf_lm75_of_id,
179351ca3e3SJean Delvare },
180922db7c5SUwe Kleine-König .probe = wf_lm75_probe,
181351ca3e3SJean Delvare .remove = wf_lm75_remove,
182351ca3e3SJean Delvare .id_table = wf_lm75_id,
183351ca3e3SJean Delvare };
184351ca3e3SJean Delvare
185f7fb862bSWei Yongjun module_i2c_driver(wf_lm75_driver);
18675722d39SBenjamin Herrenschmidt
18775722d39SBenjamin Herrenschmidt MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
18875722d39SBenjamin Herrenschmidt MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control");
18975722d39SBenjamin Herrenschmidt MODULE_LICENSE("GPL");
19075722d39SBenjamin Herrenschmidt
191