Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Windfarm PowerMac thermal control. AD7417 sensors
0004  *
0005  * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
0006  */
0007 
0008 #include <linux/types.h>
0009 #include <linux/errno.h>
0010 #include <linux/kernel.h>
0011 #include <linux/delay.h>
0012 #include <linux/slab.h>
0013 #include <linux/init.h>
0014 #include <linux/wait.h>
0015 #include <linux/i2c.h>
0016 
0017 #include <asm/machdep.h>
0018 #include <asm/io.h>
0019 #include <asm/sections.h>
0020 
0021 #include "windfarm.h"
0022 #include "windfarm_mpu.h"
0023 
0024 #define VERSION "1.0"
0025 
0026 struct wf_ad7417_priv {
0027     struct kref     ref;
0028     struct i2c_client   *i2c;
0029     u8          config;
0030     u8          cpu;
0031     const struct mpu_data   *mpu;
0032     struct wf_sensor    sensors[5];
0033     struct mutex        lock;
0034 };
0035 
0036 static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
0037 {
0038     struct wf_ad7417_priv *pv = sr->priv;
0039     u8 buf[2];
0040     s16 raw;
0041     int rc;
0042 
0043     *value = 0;
0044     mutex_lock(&pv->lock);
0045 
0046     /* Read temp register */
0047     buf[0] = 0;
0048     rc = i2c_master_send(pv->i2c, buf, 1);
0049     if (rc < 0)
0050         goto error;
0051     rc = i2c_master_recv(pv->i2c, buf, 2);
0052     if (rc < 0)
0053         goto error;
0054 
0055     /* Read a a 16-bit signed value */
0056     raw = be16_to_cpup((__le16 *)buf);
0057 
0058     /* Convert 8.8-bit to 16.16 fixed point */
0059     *value = ((s32)raw) << 8;
0060 
0061     mutex_unlock(&pv->lock);
0062     return 0;
0063 
0064 error:
0065     mutex_unlock(&pv->lock);
0066     return -1;
0067 }
0068 
0069 /*
0070  * Scaling factors for the AD7417 ADC converters (except
0071  * for the CPU diode which is obtained from the EEPROM).
0072  * Those values are obtained from the property list of
0073  * the darwin driver
0074  */
0075 #define ADC_12V_CURRENT_SCALE   0x0320  /* _AD2 */
0076 #define ADC_CPU_VOLTAGE_SCALE   0x00a0  /* _AD3 */
0077 #define ADC_CPU_CURRENT_SCALE   0x1f40  /* _AD4 */
0078 
0079 static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
0080                   int chan, s32 raw, s32 *value)
0081 {
0082     switch(chan) {
0083     case 1: /* Diode */
0084         *value = (raw * (s32)pv->mpu->mdiode +
0085             ((s32)pv->mpu->bdiode << 12)) >> 2;
0086         break;
0087     case 2: /* 12v current */
0088         *value = raw * ADC_12V_CURRENT_SCALE;
0089         break;
0090     case 3: /* core voltage */
0091         *value = raw * ADC_CPU_VOLTAGE_SCALE;
0092         break;
0093     case 4: /* core current */
0094         *value = raw * ADC_CPU_CURRENT_SCALE;
0095         break;
0096     }
0097 }
0098 
0099 static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
0100 {
0101     struct wf_ad7417_priv *pv = sr->priv;
0102     int chan = sr - pv->sensors;
0103     int i, rc;
0104     u8 buf[2];
0105     u16 raw;
0106 
0107     *value = 0;
0108     mutex_lock(&pv->lock);
0109     for (i = 0; i < 10; i++) {
0110         /* Set channel */
0111         buf[0] = 1;
0112         buf[1] = (pv->config & 0x1f) | (chan << 5);
0113         rc = i2c_master_send(pv->i2c, buf, 2);
0114         if (rc < 0)
0115             goto error;
0116 
0117         /* Wait for conversion */
0118         msleep(1);
0119 
0120         /* Switch to data register */
0121         buf[0] = 4;
0122         rc = i2c_master_send(pv->i2c, buf, 1);
0123         if (rc < 0)
0124             goto error;
0125 
0126         /* Read result */
0127         rc = i2c_master_recv(pv->i2c, buf, 2);
0128         if (rc < 0)
0129             goto error;
0130 
0131         /* Read a a 16-bit signed value */
0132         raw = be16_to_cpup((__le16 *)buf) >> 6;
0133         wf_ad7417_adc_convert(pv, chan, raw, value);
0134 
0135         dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
0136              " raw value: 0x%x, conv to: 0x%08x\n",
0137              chan, sr->name, raw, *value);
0138 
0139         mutex_unlock(&pv->lock);
0140         return 0;
0141 
0142     error:
0143         dev_dbg(&pv->i2c->dev,
0144               "Error reading ADC, try %d...\n", i);
0145         if (i < 9)
0146             msleep(10);
0147     }
0148     mutex_unlock(&pv->lock);
0149     return -1;
0150 }
0151 
0152 static void wf_ad7417_release(struct kref *ref)
0153 {
0154     struct wf_ad7417_priv *pv = container_of(ref,
0155                          struct wf_ad7417_priv, ref);
0156     kfree(pv);
0157 }
0158 
0159 static void wf_ad7417_sensor_release(struct wf_sensor *sr)
0160 {
0161     struct wf_ad7417_priv *pv = sr->priv;
0162 
0163     kfree(sr->name);
0164     kref_put(&pv->ref, wf_ad7417_release);
0165 }
0166 
0167 static const struct wf_sensor_ops wf_ad7417_temp_ops = {
0168     .get_value  = wf_ad7417_temp_get,
0169     .release    = wf_ad7417_sensor_release,
0170     .owner      = THIS_MODULE,
0171 };
0172 
0173 static const struct wf_sensor_ops wf_ad7417_adc_ops = {
0174     .get_value  = wf_ad7417_adc_get,
0175     .release    = wf_ad7417_sensor_release,
0176     .owner      = THIS_MODULE,
0177 };
0178 
0179 static void wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
0180                  int index, const char *name,
0181                  const struct wf_sensor_ops *ops)
0182 {
0183     pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
0184     pv->sensors[index].priv = pv;
0185     pv->sensors[index].ops = ops;
0186     if (!wf_register_sensor(&pv->sensors[index]))
0187         kref_get(&pv->ref);
0188 }
0189 
0190 static void wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
0191 {
0192     int rc;
0193     u8 buf[2];
0194     u8 config = 0;
0195 
0196     /*
0197      * Read ADC the configuration register and cache it. We
0198      * also make sure Config2 contains proper values, I've seen
0199      * cases where we got stale grabage in there, thus preventing
0200      * proper reading of conv. values
0201      */
0202 
0203     /* Clear Config2 */
0204     buf[0] = 5;
0205     buf[1] = 0;
0206     i2c_master_send(pv->i2c, buf, 2);
0207 
0208     /* Read & cache Config1 */
0209     buf[0] = 1;
0210     rc = i2c_master_send(pv->i2c, buf, 1);
0211     if (rc > 0) {
0212         rc = i2c_master_recv(pv->i2c, buf, 1);
0213         if (rc > 0) {
0214             config = buf[0];
0215 
0216             dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
0217                 config);
0218 
0219             /* Disable shutdown mode */
0220             config &= 0xfe;
0221             buf[0] = 1;
0222             buf[1] = config;
0223             rc = i2c_master_send(pv->i2c, buf, 2);
0224         }
0225     }
0226     if (rc <= 0)
0227         dev_err(&pv->i2c->dev, "Error reading ADC config\n");
0228 
0229     pv->config = config;
0230 }
0231 
0232 static int wf_ad7417_probe(struct i2c_client *client,
0233                const struct i2c_device_id *id)
0234 {
0235     struct wf_ad7417_priv *pv;
0236     const struct mpu_data *mpu;
0237     const char *loc;
0238     int cpu_nr;
0239 
0240     loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
0241     if (!loc) {
0242         dev_warn(&client->dev, "Missing hwsensor-location property!\n");
0243         return -ENXIO;
0244     }
0245 
0246     /*
0247      * Identify which CPU we belong to by looking at the first entry
0248      * in the hwsensor-location list
0249      */
0250     if (!strncmp(loc, "CPU A", 5))
0251         cpu_nr = 0;
0252     else if (!strncmp(loc, "CPU B", 5))
0253         cpu_nr = 1;
0254     else {
0255         pr_err("wf_ad7417: Can't identify location %s\n", loc);
0256         return -ENXIO;
0257     }
0258     mpu = wf_get_mpu(cpu_nr);
0259     if (!mpu) {
0260         dev_err(&client->dev, "Failed to retrieve MPU data\n");
0261         return -ENXIO;
0262     }
0263 
0264     pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
0265     if (pv == NULL)
0266         return -ENODEV;
0267 
0268     kref_init(&pv->ref);
0269     mutex_init(&pv->lock);
0270     pv->i2c = client;
0271     pv->cpu = cpu_nr;
0272     pv->mpu = mpu;
0273     dev_set_drvdata(&client->dev, pv);
0274 
0275     /* Initialize the chip */
0276     wf_ad7417_init_chip(pv);
0277 
0278     /*
0279      * We cannot rely on Apple device-tree giving us child
0280      * node with the names of the individual sensors so we
0281      * just hard code what we know about them
0282      */
0283     wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
0284     wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
0285     wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
0286     wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
0287     wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
0288 
0289     return 0;
0290 }
0291 
0292 static int wf_ad7417_remove(struct i2c_client *client)
0293 {
0294     struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
0295     int i;
0296 
0297     /* Mark client detached */
0298     pv->i2c = NULL;
0299 
0300     /* Release sensor */
0301     for (i = 0; i < 5; i++)
0302         wf_unregister_sensor(&pv->sensors[i]);
0303 
0304     kref_put(&pv->ref, wf_ad7417_release);
0305 
0306     return 0;
0307 }
0308 
0309 static const struct i2c_device_id wf_ad7417_id[] = {
0310     { "MAC,ad7417", 0 },
0311     { }
0312 };
0313 MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
0314 
0315 static const struct of_device_id wf_ad7417_of_id[] = {
0316     { .compatible = "ad7417", },
0317     { }
0318 };
0319 MODULE_DEVICE_TABLE(of, wf_ad7417_of_id);
0320 
0321 static struct i2c_driver wf_ad7417_driver = {
0322     .driver = {
0323         .name   = "wf_ad7417",
0324         .of_match_table = wf_ad7417_of_id,
0325     },
0326     .probe      = wf_ad7417_probe,
0327     .remove     = wf_ad7417_remove,
0328     .id_table   = wf_ad7417_id,
0329 };
0330 
0331 static int wf_ad7417_init(void)
0332 {
0333     /* This is only supported on these machines */
0334     if (!of_machine_is_compatible("PowerMac7,2") &&
0335         !of_machine_is_compatible("PowerMac7,3") &&
0336         !of_machine_is_compatible("RackMac3,1"))
0337         return -ENODEV;
0338 
0339     return i2c_add_driver(&wf_ad7417_driver);
0340 }
0341 
0342 static void wf_ad7417_exit(void)
0343 {
0344     i2c_del_driver(&wf_ad7417_driver);
0345 }
0346 
0347 module_init(wf_ad7417_init);
0348 module_exit(wf_ad7417_exit);
0349 
0350 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0351 MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
0352 MODULE_LICENSE("GPL");
0353