#include <linux/slab.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
#include <linux/moduleparam.h>
#include <linux/freezer.h>
+#include <linux/of_platform.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/sections.h>
-#include <asm/of_platform.h>
#undef DEBUG
#define CONFIG_REG 0x40
#define MANUAL_MASK 0xe0
#define AUTO_MASK 0x20
+#define INVERT_MASK 0x10
static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, sensor1, sensor2 */
static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, sensor1, sensor2 */
"(default 0)");
struct thermostat {
- struct i2c_client clt;
+ struct i2c_client *clt;
u8 temps[3];
u8 cached_temp[3];
u8 initial_limits[3];
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);
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;
-
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]);
- write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK);
+ write_reg(th, MANUAL_MODE[fan],
+ (manual|MANUAL_MASK) & (~INVERT_MASK));
write_reg(th, FAN_SPD_SET[fan], speed);
} else {
/* back to automatic */
{
struct thermostat* th = arg;
+ set_freezable();
while(!kthread_should_stop()) {
try_to_freeze();
msleep_interruptible(2000);
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 (thermostat)
return 0;
- th = (struct thermostat *)
- kmalloc(sizeof(struct thermostat), GFP_KERNEL);
-
+ th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
if (!th)
return -ENOMEM;
- memset(th, 0, sizeof(*th));
- 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);
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;
- }
-
/* be sure to really write fan speed the first time */
th->last_speed[0] = -2;
th->last_speed[1] = -2;
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
#define BUILD_STORE_FUNC_INT(name, data) \
static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
{ \
- u32 val; \
- val = simple_strtoul(buf, NULL, 10); \
+ int val; \
+ val = simple_strtol(buf, NULL, 10); \
if (val < 0 || val > 255) \
return -EINVAL; \
printk(KERN_INFO "Setting specified fan speed to %d\n", val); \
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;
- if (device_is_compatible(np, "adt7460"))
+ if (of_device_is_compatible(np, "adt7460"))
therm_type = ADT7460;
- else if (device_is_compatible(np, "adt7467"))
+ else if (of_device_is_compatible(np, "adt7467"))
therm_type = ADT7467;
- else
+ else {
+ of_node_put(np);
return -ENODEV;
+ }
- prop = get_property(np, "hwsensor-params-version", NULL);
+ prop = of_get_property(np, "hwsensor-params-version", NULL);
printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
(*prop == 1)?"":"un");
- if (*prop != 1)
+ if (*prop != 1) {
+ of_node_put(np);
return -ENODEV;
+ }
- prop = get_property(np, "reg", NULL);
- if (!prop)
+ prop = of_get_property(np, "reg", NULL);
+ if (!prop) {
+ of_node_put(np);
return -ENODEV;
+ }
/* look for bus either by path or using "reg" */
if (strstr(np->full_name, "/i2c-bus@") != NULL) {
"limit_adjust: %d, fan_speed: %d\n",
therm_bus, therm_address, limit_adjust, fan_speed);
- if (get_property(np, "hwsensor-location", NULL)) {
+ if (of_get_property(np, "hwsensor-location", NULL)) {
for (i = 0; i < 3; i++) {
- sensor_location[i] = get_property(np,
+ sensor_location[i] = of_get_property(np,
"hwsensor-location", NULL) + offset;
if (sensor_location[i] == NULL)
}
of_dev = of_platform_device_create(np, "temperatures", NULL);
-
+ of_node_put(np);
+
if (of_dev == NULL) {
printk(KERN_ERR "Can't register temperatures device !\n");
return -ENODEV;
}
-
- device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
- device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
- device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
- device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
- device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
- device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
- device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
- device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
- device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
+
+ 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);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
+ err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
+ err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
if(therm_type == ADT7460)
- device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
+ err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
+ if (err)
+ printk(KERN_WARNING
+ "Failed to create tempertaure attribute file(s).\n");
#ifndef CONFIG_I2C_POWERMAC
request_module("i2c-powermac");