Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Windfarm PowerMac thermal control. LM75 sensor
0004  *
0005  * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
0006  *                    <benh@kernel.crashing.org>
0007  */
0008 
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/kernel.h>
0012 #include <linux/delay.h>
0013 #include <linux/slab.h>
0014 #include <linux/init.h>
0015 #include <linux/wait.h>
0016 #include <linux/i2c.h>
0017 #include <linux/of_device.h>
0018 #include <asm/machdep.h>
0019 #include <asm/io.h>
0020 #include <asm/sections.h>
0021 #include <asm/pmac_low_i2c.h>
0022 
0023 #include "windfarm.h"
0024 
0025 #define VERSION "1.0"
0026 
0027 #undef DEBUG
0028 
0029 #ifdef DEBUG
0030 #define DBG(args...)    printk(args)
0031 #else
0032 #define DBG(args...)    do { } while(0)
0033 #endif
0034 
0035 struct wf_lm75_sensor {
0036     int         ds1775 : 1;
0037     int         inited : 1;
0038     struct i2c_client   *i2c;
0039     struct wf_sensor    sens;
0040 };
0041 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
0042 
0043 static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
0044 {
0045     struct wf_lm75_sensor *lm = wf_to_lm75(sr);
0046     s32 data;
0047 
0048     if (lm->i2c == NULL)
0049         return -ENODEV;
0050 
0051     /* Init chip if necessary */
0052     if (!lm->inited) {
0053         u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1);
0054 
0055         DBG("wf_lm75: Initializing %s, cfg was: %02x\n",
0056             sr->name, cfg);
0057 
0058         /* clear shutdown bit, keep other settings as left by
0059          * the firmware for now
0060          */
0061         cfg_new = cfg & ~0x01;
0062         i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new);
0063         lm->inited = 1;
0064 
0065         /* If we just powered it up, let's wait 200 ms */
0066         msleep(200);
0067     }
0068 
0069     /* Read temperature register */
0070     data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0));
0071     data <<= 8;
0072     *value = data;
0073 
0074     return 0;
0075 }
0076 
0077 static void wf_lm75_release(struct wf_sensor *sr)
0078 {
0079     struct wf_lm75_sensor *lm = wf_to_lm75(sr);
0080 
0081     kfree(lm);
0082 }
0083 
0084 static const struct wf_sensor_ops wf_lm75_ops = {
0085     .get_value  = wf_lm75_get,
0086     .release    = wf_lm75_release,
0087     .owner      = THIS_MODULE,
0088 };
0089 
0090 static int wf_lm75_probe(struct i2c_client *client,
0091              const struct i2c_device_id *id)
0092 {   
0093     struct wf_lm75_sensor *lm;
0094     int rc, ds1775;
0095     const char *name, *loc;
0096 
0097     if (id)
0098         ds1775 = id->driver_data;
0099     else
0100         ds1775 = !!of_device_get_match_data(&client->dev);
0101 
0102     DBG("wf_lm75: creating  %s device at address 0x%02x\n",
0103         ds1775 ? "ds1775" : "lm75", client->addr);
0104 
0105     loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
0106     if (!loc) {
0107         dev_warn(&client->dev, "Missing hwsensor-location property!\n");
0108         return -ENXIO;
0109     }
0110 
0111     /* Usual rant about sensor names not beeing very consistent in
0112      * the device-tree, oh well ...
0113      * Add more entries below as you deal with more setups
0114      */
0115     if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
0116         name = "hd-temp";
0117     else if (!strcmp(loc, "Incoming Air Temp"))
0118         name = "incoming-air-temp";
0119     else if (!strcmp(loc, "ODD Temp"))
0120         name = "optical-drive-temp";
0121     else if (!strcmp(loc, "HD Temp"))
0122         name = "hard-drive-temp";
0123     else if (!strcmp(loc, "PCI SLOTS"))
0124         name = "slots-temp";
0125     else if (!strcmp(loc, "CPU A INLET"))
0126         name = "cpu-inlet-temp-0";
0127     else if (!strcmp(loc, "CPU B INLET"))
0128         name = "cpu-inlet-temp-1";
0129     else
0130         return -ENXIO;
0131     
0132 
0133     lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
0134     if (lm == NULL)
0135         return -ENODEV;
0136 
0137     lm->inited = 0;
0138     lm->ds1775 = ds1775;
0139     lm->i2c = client;
0140     lm->sens.name = name;
0141     lm->sens.ops = &wf_lm75_ops;
0142     i2c_set_clientdata(client, lm);
0143 
0144     rc = wf_register_sensor(&lm->sens);
0145     if (rc)
0146         kfree(lm);
0147     return rc;
0148 }
0149 
0150 static int wf_lm75_remove(struct i2c_client *client)
0151 {
0152     struct wf_lm75_sensor *lm = i2c_get_clientdata(client);
0153 
0154     /* Mark client detached */
0155     lm->i2c = NULL;
0156 
0157     /* release sensor */
0158     wf_unregister_sensor(&lm->sens);
0159 
0160     return 0;
0161 }
0162 
0163 static const struct i2c_device_id wf_lm75_id[] = {
0164     { "MAC,lm75", 0 },
0165     { "MAC,ds1775", 1 },
0166     { }
0167 };
0168 MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
0169 
0170 static const struct of_device_id wf_lm75_of_id[] = {
0171     { .compatible = "lm75", .data = (void *)0},
0172     { .compatible = "ds1775", .data = (void *)1 },
0173     { }
0174 };
0175 MODULE_DEVICE_TABLE(of, wf_lm75_of_id);
0176 
0177 static struct i2c_driver wf_lm75_driver = {
0178     .driver = {
0179         .name   = "wf_lm75",
0180         .of_match_table = wf_lm75_of_id,
0181     },
0182     .probe      = wf_lm75_probe,
0183     .remove     = wf_lm75_remove,
0184     .id_table   = wf_lm75_id,
0185 };
0186 
0187 module_i2c_driver(wf_lm75_driver);
0188 
0189 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0190 MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control");
0191 MODULE_LICENSE("GPL");
0192