Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Device driver for the i2c thermostat found on the iBook G4, Albook G4
0004  *
0005  * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt
0006  *
0007  * Documentation from 115254175ADT7467_pra.pdf and 3686221171167ADT7460_b.pdf
0008  * https://www.onsemi.com/PowerSolutions/product.do?id=ADT7467
0009  * https://www.onsemi.com/PowerSolutions/product.do?id=ADT7460
0010  *
0011  */
0012 
0013 #include <linux/types.h>
0014 #include <linux/module.h>
0015 #include <linux/errno.h>
0016 #include <linux/kernel.h>
0017 #include <linux/delay.h>
0018 #include <linux/sched.h>
0019 #include <linux/i2c.h>
0020 #include <linux/slab.h>
0021 #include <linux/init.h>
0022 #include <linux/spinlock.h>
0023 #include <linux/wait.h>
0024 #include <linux/suspend.h>
0025 #include <linux/kthread.h>
0026 #include <linux/moduleparam.h>
0027 #include <linux/freezer.h>
0028 #include <linux/of_platform.h>
0029 
0030 #include <asm/machdep.h>
0031 #include <asm/io.h>
0032 #include <asm/sections.h>
0033 
0034 #undef DEBUG
0035 
0036 #define CONFIG_REG   0x40
0037 #define MANUAL_MASK  0xe0
0038 #define AUTO_MASK    0x20
0039 #define INVERT_MASK  0x10
0040 
0041 static u8 TEMP_REG[3]    = {0x26, 0x25, 0x27}; /* local, sensor1, sensor2 */
0042 static u8 LIMIT_REG[3]   = {0x6b, 0x6a, 0x6c}; /* local, sensor1, sensor2 */
0043 static u8 MANUAL_MODE[2] = {0x5c, 0x5d};       
0044 static u8 REM_CONTROL[2] = {0x00, 0x40};
0045 static u8 FAN_SPEED[2]   = {0x28, 0x2a};
0046 static u8 FAN_SPD_SET[2] = {0x30, 0x31};
0047 
0048 static u8 default_limits_local[3] = {70, 50, 70};    /* local, sensor1, sensor2 */
0049 static u8 default_limits_chip[3] = {80, 65, 80};    /* local, sensor1, sensor2 */
0050 static const char *sensor_location[3] = { "?", "?", "?" };
0051 
0052 static int limit_adjust;
0053 static int fan_speed = -1;
0054 static bool verbose;
0055 
0056 MODULE_AUTHOR("Colin Leroy <colin@colino.net>");
0057 MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and "
0058            "Powerbook G4 Alu");
0059 MODULE_LICENSE("GPL");
0060 
0061 module_param(limit_adjust, int, 0644);
0062 MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 sensor1, 70 sensor2) "
0063          "by N degrees.");
0064 
0065 module_param(fan_speed, int, 0644);
0066 MODULE_PARM_DESC(fan_speed,"Specify starting fan speed (0-255) "
0067          "(default 64)");
0068 
0069 module_param(verbose, bool, 0);
0070 MODULE_PARM_DESC(verbose,"Verbose log operations "
0071          "(default 0)");
0072 
0073 struct thermostat {
0074     struct i2c_client   *clt;
0075     u8          temps[3];
0076     u8          cached_temp[3];
0077     u8          initial_limits[3];
0078     u8          limits[3];
0079     int         last_speed[2];
0080     int         last_var[2];
0081     int         pwm_inv[2];
0082     struct task_struct  *thread;
0083     struct platform_device  *pdev;
0084     enum {
0085         ADT7460,
0086         ADT7467
0087     }           type;
0088 };
0089 
0090 static void write_both_fan_speed(struct thermostat *th, int speed);
0091 static void write_fan_speed(struct thermostat *th, int speed, int fan);
0092 
0093 static int
0094 write_reg(struct thermostat* th, int reg, u8 data)
0095 {
0096     u8 tmp[2];
0097     int rc;
0098     
0099     tmp[0] = reg;
0100     tmp[1] = data;
0101     rc = i2c_master_send(th->clt, (const char *)tmp, 2);
0102     if (rc < 0)
0103         return rc;
0104     if (rc != 2)
0105         return -ENODEV;
0106     return 0;
0107 }
0108 
0109 static int
0110 read_reg(struct thermostat* th, int reg)
0111 {
0112     u8 reg_addr, data;
0113     int rc;
0114 
0115     reg_addr = (u8)reg;
0116     rc = i2c_master_send(th->clt, &reg_addr, 1);
0117     if (rc < 0)
0118         return rc;
0119     if (rc != 1)
0120         return -ENODEV;
0121     rc = i2c_master_recv(th->clt, (char *)&data, 1);
0122     if (rc < 0)
0123         return rc;
0124     return data;
0125 }
0126 
0127 static int read_fan_speed(struct thermostat *th, u8 addr)
0128 {
0129     u8 tmp[2];
0130     u16 res;
0131     
0132     /* should start with low byte */
0133     tmp[1] = read_reg(th, addr);
0134     tmp[0] = read_reg(th, addr + 1);
0135     
0136     res = tmp[1] + (tmp[0] << 8);
0137     /* "a value of 0xffff means that the fan has stopped" */
0138     return (res == 0xffff ? 0 : (90000*60)/res);
0139 }
0140 
0141 static void write_both_fan_speed(struct thermostat *th, int speed)
0142 {
0143     write_fan_speed(th, speed, 0);
0144     if (th->type == ADT7460)
0145         write_fan_speed(th, speed, 1);
0146 }
0147 
0148 static void write_fan_speed(struct thermostat *th, int speed, int fan)
0149 {
0150     u8 manual;
0151     
0152     if (speed > 0xff) 
0153         speed = 0xff;
0154     else if (speed < -1) 
0155         speed = 0;
0156     
0157     if (th->type == ADT7467 && fan == 1)
0158         return;
0159     
0160     if (th->last_speed[fan] != speed) {
0161         if (verbose) {
0162             if (speed == -1)
0163                 printk(KERN_DEBUG "adt746x: Setting speed to automatic "
0164                     "for %s fan.\n", sensor_location[fan+1]);
0165             else
0166                 printk(KERN_DEBUG "adt746x: Setting speed to %d "
0167                     "for %s fan.\n", speed, sensor_location[fan+1]);
0168         }
0169     } else
0170         return;
0171     
0172     if (speed >= 0) {
0173         manual = read_reg(th, MANUAL_MODE[fan]);
0174         manual &= ~INVERT_MASK;
0175         write_reg(th, MANUAL_MODE[fan],
0176             manual | MANUAL_MASK | th->pwm_inv[fan]);
0177         write_reg(th, FAN_SPD_SET[fan], speed);
0178     } else {
0179         /* back to automatic */
0180         if(th->type == ADT7460) {
0181             manual = read_reg(th,
0182                 MANUAL_MODE[fan]) & (~MANUAL_MASK);
0183             manual &= ~INVERT_MASK;
0184             manual |= th->pwm_inv[fan];
0185             write_reg(th,
0186                 MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
0187         } else {
0188             manual = read_reg(th, MANUAL_MODE[fan]);
0189             manual &= ~INVERT_MASK;
0190             manual |= th->pwm_inv[fan];
0191             write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
0192         }
0193     }
0194     
0195     th->last_speed[fan] = speed;            
0196 }
0197 
0198 static void read_sensors(struct thermostat *th)
0199 {
0200     int i = 0;
0201 
0202     for (i = 0; i < 3; i++)
0203         th->temps[i]  = read_reg(th, TEMP_REG[i]);
0204 }
0205 
0206 #ifdef DEBUG
0207 static void display_stats(struct thermostat *th)
0208 {
0209     if (th->temps[0] != th->cached_temp[0]
0210     ||  th->temps[1] != th->cached_temp[1]
0211     ||  th->temps[2] != th->cached_temp[2]) {
0212         printk(KERN_INFO "adt746x: Temperature infos:"
0213                  " thermostats: %d,%d,%d;"
0214                  " limits: %d,%d,%d;"
0215                  " fan speed: %d RPM\n",
0216                  th->temps[0], th->temps[1], th->temps[2],
0217                  th->limits[0],  th->limits[1],  th->limits[2],
0218                  read_fan_speed(th, FAN_SPEED[0]));
0219     }
0220     th->cached_temp[0] = th->temps[0];
0221     th->cached_temp[1] = th->temps[1];
0222     th->cached_temp[2] = th->temps[2];
0223 }
0224 #endif
0225 
0226 static void update_fans_speed (struct thermostat *th)
0227 {
0228     int lastvar = 0; /* last variation, for iBook */
0229     int i = 0;
0230 
0231     /* we don't care about local sensor, so we start at sensor 1 */
0232     for (i = 1; i < 3; i++) {
0233         bool started = false;
0234         int fan_number = (th->type == ADT7460 && i == 2);
0235         int var = th->temps[i] - th->limits[i];
0236 
0237         if (var > -1) {
0238             int step = (255 - fan_speed) / 7;
0239             int new_speed = 0;
0240 
0241             /* hysteresis : change fan speed only if variation is
0242              * more than two degrees */
0243             if (abs(var - th->last_var[fan_number]) < 2)
0244                 continue;
0245 
0246             started = true;
0247             new_speed = fan_speed + ((var-1)*step);
0248 
0249             if (new_speed < fan_speed)
0250                 new_speed = fan_speed;
0251             if (new_speed > 255)
0252                 new_speed = 255;
0253 
0254             if (verbose)
0255                 printk(KERN_DEBUG "adt746x: Setting fans speed to %d "
0256                          "(limit exceeded by %d on %s)\n",
0257                         new_speed, var,
0258                         sensor_location[fan_number+1]);
0259             write_both_fan_speed(th, new_speed);
0260             th->last_var[fan_number] = var;
0261         } else if (var < -2) {
0262             /* don't stop fan if sensor2 is cold and sensor1 is not
0263              * so cold (lastvar >= -1) */
0264             if (i == 2 && lastvar < -1) {
0265                 if (th->last_speed[fan_number] != 0)
0266                     if (verbose)
0267                         printk(KERN_DEBUG "adt746x: Stopping "
0268                             "fans.\n");
0269                 write_both_fan_speed(th, 0);
0270             }
0271         }
0272 
0273         lastvar = var;
0274 
0275         if (started)
0276             return; /* we don't want to re-stop the fan
0277                 * if sensor1 is heating and sensor2 is not */
0278     }
0279 }
0280 
0281 static int monitor_task(void *arg)
0282 {
0283     struct thermostat* th = arg;
0284 
0285     set_freezable();
0286     while(!kthread_should_stop()) {
0287         try_to_freeze();
0288         msleep_interruptible(2000);
0289 
0290 #ifndef DEBUG
0291         if (fan_speed != -1)
0292             read_sensors(th);
0293 #else
0294         read_sensors(th);
0295 #endif      
0296 
0297         if (fan_speed != -1)
0298             update_fans_speed(th);
0299 
0300 #ifdef DEBUG
0301         display_stats(th);
0302 #endif
0303 
0304     }
0305 
0306     return 0;
0307 }
0308 
0309 static void set_limit(struct thermostat *th, int i)
0310 {
0311     /* Set sensor1 limit higher to avoid powerdowns */
0312     th->limits[i] = default_limits_chip[i] + limit_adjust;
0313     write_reg(th, LIMIT_REG[i], th->limits[i]);
0314         
0315     /* set our limits to normal */
0316     th->limits[i] = default_limits_local[i] + limit_adjust;
0317 }
0318 
0319 #define BUILD_SHOW_FUNC_INT(name, data)             \
0320 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)    \
0321 {                               \
0322     struct thermostat *th = dev_get_drvdata(dev);       \
0323     return sprintf(buf, "%d\n", data);          \
0324 }
0325 
0326 #define BUILD_SHOW_FUNC_INT_LITE(name, data)                \
0327 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)    \
0328 {                               \
0329     return sprintf(buf, "%d\n", data);          \
0330 }
0331 
0332 #define BUILD_SHOW_FUNC_STR(name, data)             \
0333 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
0334 {                               \
0335     return sprintf(buf, "%s\n", data);          \
0336 }
0337 
0338 #define BUILD_SHOW_FUNC_FAN(name, data)             \
0339 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
0340 {                               \
0341     struct thermostat *th = dev_get_drvdata(dev);       \
0342     return sprintf(buf, "%d (%d rpm)\n",            \
0343         th->last_speed[data],               \
0344         read_fan_speed(th, FAN_SPEED[data])     \
0345         );                      \
0346 }
0347 
0348 #define BUILD_STORE_FUNC_DEG(name, data)            \
0349 static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
0350 {                               \
0351     struct thermostat *th = dev_get_drvdata(dev);       \
0352     int val;                        \
0353     int i;                          \
0354     val = simple_strtol(buf, NULL, 10);         \
0355     printk(KERN_INFO "Adjusting limits by %d degrees\n", val);  \
0356     limit_adjust = val;                 \
0357     for (i=0; i < 3; i++)                   \
0358         set_limit(th, i);               \
0359     return n;                       \
0360 }
0361 
0362 #define BUILD_STORE_FUNC_INT(name, data)            \
0363 static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
0364 {                               \
0365     int val;                        \
0366     val = simple_strtol(buf, NULL, 10);         \
0367     if (val < 0 || val > 255)               \
0368         return -EINVAL;                 \
0369     printk(KERN_INFO "Setting specified fan speed to %d\n", val);   \
0370     data = val;                     \
0371     return n;                       \
0372 }
0373 
0374 BUILD_SHOW_FUNC_INT(sensor1_temperature,     (read_reg(th, TEMP_REG[1])))
0375 BUILD_SHOW_FUNC_INT(sensor2_temperature,     (read_reg(th, TEMP_REG[2])))
0376 BUILD_SHOW_FUNC_INT(sensor1_limit,       th->limits[1])
0377 BUILD_SHOW_FUNC_INT(sensor2_limit,       th->limits[2])
0378 BUILD_SHOW_FUNC_STR(sensor1_location,        sensor_location[1])
0379 BUILD_SHOW_FUNC_STR(sensor2_location,        sensor_location[2])
0380 
0381 BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed)
0382 BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
0383 
0384 BUILD_SHOW_FUNC_FAN(sensor1_fan_speed,   0)
0385 BUILD_SHOW_FUNC_FAN(sensor2_fan_speed,   1)
0386 
0387 BUILD_SHOW_FUNC_INT_LITE(limit_adjust,   limit_adjust)
0388 BUILD_STORE_FUNC_DEG(limit_adjust,   th)
0389         
0390 static DEVICE_ATTR(sensor1_temperature, S_IRUGO,
0391            show_sensor1_temperature,NULL);
0392 static DEVICE_ATTR(sensor2_temperature, S_IRUGO,
0393            show_sensor2_temperature,NULL);
0394 static DEVICE_ATTR(sensor1_limit, S_IRUGO,
0395            show_sensor1_limit,  NULL);
0396 static DEVICE_ATTR(sensor2_limit, S_IRUGO,
0397            show_sensor2_limit,  NULL);
0398 static DEVICE_ATTR(sensor1_location, S_IRUGO,
0399            show_sensor1_location, NULL);
0400 static DEVICE_ATTR(sensor2_location, S_IRUGO,
0401            show_sensor2_location, NULL);
0402 
0403 static DEVICE_ATTR(specified_fan_speed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
0404            show_specified_fan_speed,store_specified_fan_speed);
0405 
0406 static DEVICE_ATTR(sensor1_fan_speed,   S_IRUGO,
0407            show_sensor1_fan_speed,  NULL);
0408 static DEVICE_ATTR(sensor2_fan_speed,   S_IRUGO,
0409            show_sensor2_fan_speed,  NULL);
0410 
0411 static DEVICE_ATTR(limit_adjust,    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
0412            show_limit_adjust,   store_limit_adjust);
0413 
0414 static void thermostat_create_files(struct thermostat *th)
0415 {
0416     struct device_node *np = th->clt->dev.of_node;
0417     struct device *dev;
0418     int err;
0419 
0420     /* To maintain ABI compatibility with userspace, create
0421      * the old style platform driver and attach the attributes
0422      * to it here
0423      */
0424     th->pdev = of_platform_device_create(np, "temperatures", NULL);
0425     if (!th->pdev)
0426         return;
0427     dev = &th->pdev->dev;
0428     dev_set_drvdata(dev, th);
0429     err = device_create_file(dev, &dev_attr_sensor1_temperature);
0430     err |= device_create_file(dev, &dev_attr_sensor2_temperature);
0431     err |= device_create_file(dev, &dev_attr_sensor1_limit);
0432     err |= device_create_file(dev, &dev_attr_sensor2_limit);
0433     err |= device_create_file(dev, &dev_attr_sensor1_location);
0434     err |= device_create_file(dev, &dev_attr_sensor2_location);
0435     err |= device_create_file(dev, &dev_attr_limit_adjust);
0436     err |= device_create_file(dev, &dev_attr_specified_fan_speed);
0437     err |= device_create_file(dev, &dev_attr_sensor1_fan_speed);
0438     if(th->type == ADT7460)
0439         err |= device_create_file(dev, &dev_attr_sensor2_fan_speed);
0440     if (err)
0441         printk(KERN_WARNING
0442             "Failed to create temperature attribute file(s).\n");
0443 }
0444 
0445 static void thermostat_remove_files(struct thermostat *th)
0446 {
0447     struct device *dev;
0448 
0449     if (!th->pdev)
0450         return;
0451     dev = &th->pdev->dev;
0452     device_remove_file(dev, &dev_attr_sensor1_temperature);
0453     device_remove_file(dev, &dev_attr_sensor2_temperature);
0454     device_remove_file(dev, &dev_attr_sensor1_limit);
0455     device_remove_file(dev, &dev_attr_sensor2_limit);
0456     device_remove_file(dev, &dev_attr_sensor1_location);
0457     device_remove_file(dev, &dev_attr_sensor2_location);
0458     device_remove_file(dev, &dev_attr_limit_adjust);
0459     device_remove_file(dev, &dev_attr_specified_fan_speed);
0460     device_remove_file(dev, &dev_attr_sensor1_fan_speed);   
0461     if (th->type == ADT7460)
0462         device_remove_file(dev, &dev_attr_sensor2_fan_speed);
0463     of_device_unregister(th->pdev);
0464 
0465 }
0466 
0467 static int probe_thermostat(struct i2c_client *client,
0468                 const struct i2c_device_id *id)
0469 {
0470     struct device_node *np = client->dev.of_node;
0471     struct thermostat* th;
0472     const __be32 *prop;
0473     int i, rc, vers, offset = 0;
0474 
0475     if (!np)
0476         return -ENXIO;
0477     prop = of_get_property(np, "hwsensor-params-version", NULL);
0478     if (!prop)
0479         return -ENXIO;
0480     vers = be32_to_cpup(prop);
0481     printk(KERN_INFO "adt746x: version %d (%ssupported)\n",
0482            vers, vers == 1 ? "" : "un");
0483     if (vers != 1)
0484         return -ENXIO;
0485 
0486     if (of_get_property(np, "hwsensor-location", NULL)) {
0487         for (i = 0; i < 3; i++) {
0488             sensor_location[i] = of_get_property(np,
0489                     "hwsensor-location", NULL) + offset;
0490 
0491             if (sensor_location[i] == NULL)
0492                 sensor_location[i] = "";
0493 
0494             printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
0495             offset += strlen(sensor_location[i]) + 1;
0496         }
0497     }
0498 
0499     th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
0500     if (!th)
0501         return -ENOMEM;
0502 
0503     i2c_set_clientdata(client, th);
0504     th->clt = client;
0505     th->type = id->driver_data;
0506 
0507     rc = read_reg(th, CONFIG_REG);
0508     if (rc < 0) {
0509         dev_err(&client->dev, "Thermostat failed to read config!\n");
0510         kfree(th);
0511         return -ENODEV;
0512     }
0513 
0514     /* force manual control to start the fan quieter */
0515     if (fan_speed == -1)
0516         fan_speed = 64;
0517     
0518     if (th->type == ADT7460) {
0519         printk(KERN_INFO "adt746x: ADT7460 initializing\n");
0520         /* The 7460 needs to be started explicitly */
0521         write_reg(th, CONFIG_REG, 1);
0522     } else
0523         printk(KERN_INFO "adt746x: ADT7467 initializing\n");
0524 
0525     for (i = 0; i < 3; i++) {
0526         th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
0527         set_limit(th, i);
0528     }
0529 
0530     printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
0531              " to %d, %d, %d\n",
0532              th->initial_limits[0], th->initial_limits[1],
0533              th->initial_limits[2], th->limits[0], th->limits[1],
0534              th->limits[2]);
0535 
0536     /* record invert bit status because fw can corrupt it after suspend */
0537     th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
0538     th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
0539 
0540     /* be sure to really write fan speed the first time */
0541     th->last_speed[0] = -2;
0542     th->last_speed[1] = -2;
0543     th->last_var[0] = -80;
0544     th->last_var[1] = -80;
0545 
0546     if (fan_speed != -1) {
0547         /* manual mode, stop fans */
0548         write_both_fan_speed(th, 0);
0549     } else {
0550         /* automatic mode */
0551         write_both_fan_speed(th, -1);
0552     }
0553     
0554     th->thread = kthread_run(monitor_task, th, "kfand");
0555     if (th->thread == ERR_PTR(-ENOMEM)) {
0556         printk(KERN_INFO "adt746x: Kthread creation failed\n");
0557         th->thread = NULL;
0558         return -ENOMEM;
0559     }
0560 
0561     thermostat_create_files(th);
0562 
0563     return 0;
0564 }
0565 
0566 static int remove_thermostat(struct i2c_client *client)
0567 {
0568     struct thermostat *th = i2c_get_clientdata(client);
0569     int i;
0570     
0571     thermostat_remove_files(th);
0572 
0573     if (th->thread != NULL)
0574         kthread_stop(th->thread);
0575 
0576     printk(KERN_INFO "adt746x: Putting max temperatures back from "
0577              "%d, %d, %d to %d, %d, %d\n",
0578         th->limits[0], th->limits[1], th->limits[2],
0579         th->initial_limits[0], th->initial_limits[1],
0580         th->initial_limits[2]);
0581 
0582     for (i = 0; i < 3; i++)
0583         write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
0584 
0585     write_both_fan_speed(th, -1);
0586 
0587     kfree(th);
0588 
0589     return 0;
0590 }
0591 
0592 static const struct i2c_device_id therm_adt746x_id[] = {
0593     { "MAC,adt7460", ADT7460 },
0594     { "MAC,adt7467", ADT7467 },
0595     { }
0596 };
0597 MODULE_DEVICE_TABLE(i2c, therm_adt746x_id);
0598 
0599 static struct i2c_driver thermostat_driver = {
0600     .driver = {
0601         .name   = "therm_adt746x",
0602     },
0603     .probe = probe_thermostat,
0604     .remove = remove_thermostat,
0605     .id_table = therm_adt746x_id,
0606 };
0607 
0608 static int __init thermostat_init(void)
0609 {
0610 #ifndef CONFIG_I2C_POWERMAC
0611     request_module("i2c-powermac");
0612 #endif
0613 
0614     return i2c_add_driver(&thermostat_driver);
0615 }
0616 
0617 static void __exit thermostat_exit(void)
0618 {
0619     i2c_del_driver(&thermostat_driver);
0620 }
0621 
0622 module_init(thermostat_init);
0623 module_exit(thermostat_exit);