xref: /linux/drivers/macintosh/windfarm_lm75_sensor.c (revision a23e1966932464e1c5226cb9ac4ce1d5fc10ba22)
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