"(default 0)");
struct thermostat {
- struct i2c_client clt;
+ struct i2c_client *clt;
u8 temps[3];
u8 cached_temp[3];
u8 initial_limits[3];
u8 limits[3];
int last_speed[2];
int last_var[2];
+ int pwm_inv[2];
};
static enum {ADT7460, ADT7467} therm_type;
static struct thermostat* thermostat;
static struct task_struct *thread_therm = NULL;
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
- int busno);
-
static void write_both_fan_speed(struct thermostat *th, int speed);
static void write_fan_speed(struct thermostat *th, int speed, int fan);
+static void thermostat_create_files(void);
+static void thermostat_remove_files(void);
static int
write_reg(struct thermostat* th, int reg, u8 data)
tmp[0] = reg;
tmp[1] = data;
- rc = i2c_master_send(&th->clt, (const char *)tmp, 2);
+ rc = i2c_master_send(th->clt, (const char *)tmp, 2);
if (rc < 0)
return rc;
if (rc != 2)
int rc;
reg_addr = (u8)reg;
- rc = i2c_master_send(&th->clt, ®_addr, 1);
+ rc = i2c_master_send(th->clt, ®_addr, 1);
if (rc < 0)
return rc;
if (rc != 1)
return -ENODEV;
- rc = i2c_master_recv(&th->clt, (char *)&data, 1);
+ rc = i2c_master_recv(th->clt, (char *)&data, 1);
if (rc < 0)
return rc;
return data;
}
+static struct i2c_driver thermostat_driver;
+
static int
attach_thermostat(struct i2c_adapter *adapter)
{
unsigned long bus_no;
+ struct i2c_board_info info;
+ struct i2c_client *client;
if (strncmp(adapter->name, "uni-n", 5))
return -ENODEV;
bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
if (bus_no != therm_bus)
return -ENODEV;
- return attach_one_thermostat(adapter, therm_address, bus_no);
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
+ info.addr = therm_address;
+ client = i2c_new_device(adapter, &info);
+ if (!client)
+ return -ENODEV;
+
+ /*
+ * Let i2c-core delete that device on driver removal.
+ * This is safe because i2c-core holds the core_lock mutex for us.
+ */
+ list_add_tail(&client->detected, &thermostat_driver.clients);
+ return 0;
}
static int
-detach_thermostat(struct i2c_adapter *adapter)
+remove_thermostat(struct i2c_client *client)
{
- struct thermostat* th;
+ struct thermostat *th = i2c_get_clientdata(client);
int i;
- if (thermostat == NULL)
- return 0;
-
- th = thermostat;
+ thermostat_remove_files();
if (thread_therm != NULL) {
kthread_stop(thread_therm);
write_both_fan_speed(th, -1);
- i2c_detach_client(&th->clt);
-
thermostat = NULL;
kfree(th);
return 0;
}
-static struct i2c_driver thermostat_driver = {
- .driver = {
- .name = "therm_adt746x",
- },
- .attach_adapter = attach_thermostat,
- .detach_adapter = detach_thermostat,
-};
-
static int read_fan_speed(struct thermostat *th, u8 addr)
{
u8 tmp[2];
if (speed >= 0) {
manual = read_reg(th, MANUAL_MODE[fan]);
+ manual &= ~INVERT_MASK;
write_reg(th, MANUAL_MODE[fan],
- (manual|MANUAL_MASK) & (~INVERT_MASK));
+ manual | MANUAL_MASK | th->pwm_inv[fan]);
write_reg(th, FAN_SPD_SET[fan], speed);
} else {
/* back to automatic */
if(therm_type == ADT7460) {
manual = read_reg(th,
MANUAL_MODE[fan]) & (~MANUAL_MASK);
-
+ manual &= ~INVERT_MASK;
+ manual |= th->pwm_inv[fan];
write_reg(th,
MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
} else {
manual = read_reg(th, MANUAL_MODE[fan]);
+ manual &= ~INVERT_MASK;
+ manual |= th->pwm_inv[fan];
write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
}
}
if (verbose)
printk(KERN_DEBUG "adt746x: Setting fans speed to %d "
- "(limit exceeded by %d on %s) \n",
+ "(limit exceeded by %d on %s)\n",
new_speed, var,
sensor_location[fan_number+1]);
write_both_fan_speed(th, new_speed);
th->limits[i] = default_limits_local[i] + limit_adjust;
}
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
- int busno)
+static int probe_thermostat(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct thermostat* th;
int rc;
if (!th)
return -ENOMEM;
- th->clt.addr = addr;
- th->clt.adapter = adapter;
- th->clt.driver = &thermostat_driver;
- strcpy(th->clt.name, "thermostat");
+ i2c_set_clientdata(client, th);
+ th->clt = client;
- rc = read_reg(th, 0);
+ rc = read_reg(th, CONFIG_REG);
if (rc < 0) {
- printk(KERN_ERR "adt746x: Thermostat failed to read config "
- "from bus %d !\n",
- busno);
+ dev_err(&client->dev, "Thermostat failed to read config!\n");
kfree(th);
return -ENODEV;
}
thermostat = th;
- if (i2c_attach_client(&th->clt)) {
- printk(KERN_INFO "adt746x: Thermostat failed to attach "
- "client !\n");
- thermostat = NULL;
- kfree(th);
- return -ENODEV;
- }
+ /* record invert bit status because fw can corrupt it after suspend */
+ th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
+ th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
/* be sure to really write fan speed the first time */
th->last_speed[0] = -2;
return -ENOMEM;
}
+ thermostat_create_files();
+
return 0;
}
+static const struct i2c_device_id therm_adt746x_id[] = {
+ { "therm_adt746x", 0 },
+ { }
+};
+
+static struct i2c_driver thermostat_driver = {
+ .driver = {
+ .name = "therm_adt746x",
+ },
+ .attach_adapter = attach_thermostat,
+ .probe = probe_thermostat,
+ .remove = remove_thermostat,
+ .id_table = therm_adt746x_id,
+};
+
/*
* Now, unfortunately, sysfs doesn't give us a nice void * we could
* pass around to the attribute functions, so we don't really have
struct device_node* np;
const u32 *prop;
int i = 0, offset = 0;
- int err;
np = of_find_node_by_name(NULL, "fan");
if (!np)
return -ENODEV;
}
+#ifndef CONFIG_I2C_POWERMAC
+ request_module("i2c-powermac");
+#endif
+
+ return i2c_add_driver(&thermostat_driver);
+}
+
+static void thermostat_create_files(void)
+{
+ int err;
+
err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
if (err)
printk(KERN_WARNING
"Failed to create tempertaure attribute file(s).\n");
-
-#ifndef CONFIG_I2C_POWERMAC
- request_module("i2c-powermac");
-#endif
-
- return i2c_add_driver(&thermostat_driver);
}
-static void __exit
-thermostat_exit(void)
+static void thermostat_remove_files(void)
{
if (of_dev) {
device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
device_remove_file(&of_dev->dev,
&dev_attr_sensor2_fan_speed);
- of_device_unregister(of_dev);
}
+}
+
+static void __exit
+thermostat_exit(void)
+{
i2c_del_driver(&thermostat_driver);
+ of_device_unregister(of_dev);
}
module_init(thermostat_init);