root/drivers/macintosh/windfarm_lm87_sensor.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wf_lm87_read_reg
  2. wf_lm87_get
  3. wf_lm87_release
  4. wf_lm87_probe
  5. wf_lm87_remove
  6. wf_lm87_sensor_init
  7. wf_lm87_sensor_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Windfarm PowerMac thermal control. LM87 sensor
   4  *
   5  * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
   6  */
   7 
   8 #include <linux/types.h>
   9 #include <linux/errno.h>
  10 #include <linux/kernel.h>
  11 #include <linux/delay.h>
  12 #include <linux/slab.h>
  13 #include <linux/init.h>
  14 #include <linux/wait.h>
  15 #include <linux/i2c.h>
  16 #include <asm/prom.h>
  17 #include <asm/machdep.h>
  18 #include <asm/io.h>
  19 #include <asm/sections.h>
  20 #include <asm/pmac_low_i2c.h>
  21 
  22 #include "windfarm.h"
  23 
  24 #define VERSION "1.0"
  25 
  26 #undef DEBUG
  27 
  28 #ifdef DEBUG
  29 #define DBG(args...)    printk(args)
  30 #else
  31 #define DBG(args...)    do { } while(0)
  32 #endif
  33 
  34 struct wf_lm87_sensor {
  35         struct i2c_client       *i2c;
  36         struct wf_sensor        sens;
  37 };
  38 #define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
  39 
  40 
  41 static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
  42 {
  43         int rc, tries = 0;
  44         u8 buf;
  45 
  46         for (;;) {
  47                 /* Set address */
  48                 buf = (u8)reg;
  49                 rc = i2c_master_send(chip, &buf, 1);
  50                 if (rc <= 0)
  51                         goto error;
  52                 rc = i2c_master_recv(chip, &buf, 1);
  53                 if (rc <= 0)
  54                         goto error;
  55                 return (int)buf;
  56         error:
  57                 DBG("wf_lm87: Error reading LM87, retrying...\n");
  58                 if (++tries > 10) {
  59                         printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
  60                         return -EIO;
  61                 }
  62                 msleep(10);
  63         }
  64 }
  65 
  66 static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
  67 {
  68         struct wf_lm87_sensor *lm = sr->priv;
  69         s32 temp;
  70 
  71         if (lm->i2c == NULL)
  72                 return -ENODEV;
  73 
  74 #define LM87_INT_TEMP           0x27
  75 
  76         /* Read temperature register */
  77         temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
  78         if (temp < 0)
  79                 return temp;
  80         *value = temp << 16;
  81 
  82         return 0;
  83 }
  84 
  85 static void wf_lm87_release(struct wf_sensor *sr)
  86 {
  87         struct wf_lm87_sensor *lm = wf_to_lm87(sr);
  88 
  89         kfree(lm);
  90 }
  91 
  92 static const struct wf_sensor_ops wf_lm87_ops = {
  93         .get_value      = wf_lm87_get,
  94         .release        = wf_lm87_release,
  95         .owner          = THIS_MODULE,
  96 };
  97 
  98 static int wf_lm87_probe(struct i2c_client *client,
  99                          const struct i2c_device_id *id)
 100 {       
 101         struct wf_lm87_sensor *lm;
 102         const char *name = NULL, *loc;
 103         struct device_node *np = NULL;
 104         int rc;
 105 
 106         /*
 107          * The lm87 contains a whole pile of sensors, additionally,
 108          * the Xserve G5 has several lm87's. However, for now we only
 109          * care about the internal temperature sensor
 110          */
 111         for_each_child_of_node(client->dev.of_node, np) {
 112                 if (!of_node_name_eq(np, "int-temp"))
 113                         continue;
 114                 loc = of_get_property(np, "location", NULL);
 115                 if (!loc)
 116                         continue;
 117                 if (strstr(loc, "DIMM"))
 118                         name = "dimms-temp";
 119                 else if (strstr(loc, "Processors"))
 120                         name = "between-cpus-temp";
 121                 if (name) {
 122                         of_node_put(np);
 123                         break;
 124                 }
 125         }
 126         if (!name) {
 127                 pr_warning("wf_lm87: Unsupported sensor %pOF\n",
 128                            client->dev.of_node);
 129                 return -ENODEV;
 130         }
 131 
 132         lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
 133         if (lm == NULL)
 134                 return -ENODEV;
 135 
 136         lm->i2c = client;
 137         lm->sens.name = name;
 138         lm->sens.ops = &wf_lm87_ops;
 139         lm->sens.priv = lm;
 140         i2c_set_clientdata(client, lm);
 141 
 142         rc = wf_register_sensor(&lm->sens);
 143         if (rc)
 144                 kfree(lm);
 145         return rc;
 146 }
 147 
 148 static int wf_lm87_remove(struct i2c_client *client)
 149 {
 150         struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
 151 
 152         DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
 153 
 154         /* Mark client detached */
 155         lm->i2c = NULL;
 156 
 157         /* release sensor */
 158         wf_unregister_sensor(&lm->sens);
 159 
 160         return 0;
 161 }
 162 
 163 static const struct i2c_device_id wf_lm87_id[] = {
 164         { "MAC,lm87cimt", 0 },
 165         { }
 166 };
 167 MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
 168 
 169 static const struct of_device_id wf_lm87_of_id[] = {
 170         { .compatible = "lm87cimt", },
 171         { }
 172 };
 173 MODULE_DEVICE_TABLE(of, wf_lm87_of_id);
 174 
 175 static struct i2c_driver wf_lm87_driver = {
 176         .driver = {
 177                 .name   = "wf_lm87",
 178                 .of_match_table = wf_lm87_of_id,
 179         },
 180         .probe          = wf_lm87_probe,
 181         .remove         = wf_lm87_remove,
 182         .id_table       = wf_lm87_id,
 183 };
 184 
 185 static int __init wf_lm87_sensor_init(void)
 186 {
 187         /* We only support this on the Xserve */
 188         if (!of_machine_is_compatible("RackMac3,1"))
 189                 return -ENODEV;
 190 
 191         return i2c_add_driver(&wf_lm87_driver);
 192 }
 193 
 194 static void __exit wf_lm87_sensor_exit(void)
 195 {
 196         i2c_del_driver(&wf_lm87_driver);
 197 }
 198 
 199 
 200 module_init(wf_lm87_sensor_init);
 201 module_exit(wf_lm87_sensor_exit);
 202 
 203 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 204 MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
 205 MODULE_LICENSE("GPL");
 206 

/* [<][>][^][v][top][bottom][index][help] */