Skip to contentSkip to conversation

PowerMac i2c API conversions & windfarm updates

PATCH In review Benjamin Herrenschmidt 4 participants 37 messages Apr 19, 2012 – Jun 18, 2012 5 messages not in the archive

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover PowerMac i2c API conversions & windfarm updates

The goal of this series is to convert a bulk of PowerMac i2c drivers to the new "proper" i2c driver registration model. This series is not complete in that there are still a few drivers to do but it goes through the bulk of thermal control and some of the nastiest.

The biggest change is that windfarm is ported to generally use the new model, and I've written a new set of windfarm modules to take over from the old therm_pm72 (which was mostly unfixable) on the PowerMac G5 AGP and Xserve G5 machines.

This had a bit of testing on a couple of PowerMac G5 AGP variants but none at all on Xserve G5 since the one I have is unfortunately dead.

If you want to help me test this, don't forget to disable therm_pm72, and instead load windfarm_pm72 or windfarm_rm31 depending on your machine (you can load or build-in the whole lot as well). As usual windfarm don't properly auto-load yet, I still need to fix that.

So please test ! Especially if you have an XServe G5

#1 lore raw

PATCH 1/15 i2c/powermac: Register i2c devices from device-tree

This causes i2c-powermac to register i2c devices exposed in the device-tree, enabling new-style probing of devices.

Note that we prefix the IDs with "MAC," in order to prevent the generic drivers from matching. This is done on purpose as we only want drivers specifically tested/designed to operate on powermacs to match.

This removes the special case we had for the AMS driver, and updates the driver's match table instead.

---
 arch/powerpc/platforms/powermac/low_i2c.c |    1 +
 drivers/i2c/busses/i2c-powermac.c         |   98 +++++++++++++++++++++--------
 drivers/macintosh/ams/ams-i2c.c           |    2 +-
 3 files changed, 73 insertions(+), 28 deletions(-)
arch/powerpc/platforms/powermac/low_i2c.c +1 -0
index 996c5ff..f991dbb 100644
@@ -1494,6 +1494,7 @@ static int __init pmac_i2c_create_platform_devices(void)
 		if (bus->platform_dev == NULL)
 			return -ENOMEM;
 		bus->platform_dev->dev.platform_data = bus;
+		bus->platform_dev->dev.of_node = bus->busnode;
 		platform_device_add(bus->platform_dev);
 	}
 
drivers/i2c/busses/i2c-powermac.c +71 -27

116 lines not on this page · raw message

drivers/macintosh/ams/ams-i2c.c +1 -1
index abeecd2..978eda8 100644
@@ -65,7 +65,7 @@ static int ams_i2c_probe(struct i2c_client *client,
 static int ams_i2c_remove(struct i2c_client *client);
 
 static const struct i2c_device_id ams_id[] = {
-	{ "ams", 0 },
+	{ "MAC,accelerometer_1", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ams_id);
Signature · 1 line
1.7.9.5
#2 lore raw

PATCH 2/15 powerpc/pmac: Convert therm_adt746x to new i2c probing

In reply to Benjamin Herrenschmidt

This simplifies the driver to stop using the deprecated attach interface,

---
 drivers/macintosh/therm_adt746x.c |  480 ++++++++++++++++---------------------
 1 file changed, 204 insertions(+), 276 deletions(-)
drivers/macintosh/therm_adt746x.c +204 -276
index fc71723..f433521 100644
@@ -47,7 +47,7 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
 
 static u8 default_limits_local[3] = {70, 50, 70};    /* local, sensor1, sensor2 */
 static u8 default_limits_chip[3] = {80, 65, 80};    /* local, sensor1, sensor2 */
-static const char *sensor_location[3];
+static const char *sensor_location[3] = { "?", "?", "?" };
 
 static int limit_adjust;
 static int fan_speed = -1;
@@ -79,18 +79,16 @@ struct thermostat {
 	int			last_speed[2];
 	int			last_var[2];
 	int			pwm_inv[2];
+	struct task_struct	*thread;
+	struct platform_device	*pdev;
+	enum {
+		ADT7460,
+		ADT7467
+	}			type;
 };
 
-static enum {ADT7460, ADT7467} therm_type;
-static int therm_bus, therm_address;
-static struct platform_device * of_dev;
-static struct thermostat* thermostat;
-static struct task_struct *thread_therm = NULL;
-
 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)
@@ -126,66 +124,6 @@ read_reg(struct thermostat* th, int reg)
 	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;
-
-	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
-remove_thermostat(struct i2c_client *client)
-{
-	struct thermostat *th = i2c_get_clientdata(client);
-	int i;
-	
-	thermostat_remove_files();
-
-	if (thread_therm != NULL) {
-		kthread_stop(thread_therm);
-	}
-
-	printk(KERN_INFO "adt746x: Putting max temperatures back from "
-			 "%d, %d, %d to %d, %d, %d\n",
-		th->limits[0], th->limits[1], th->limits[2],
-		th->initial_limits[0], th->initial_limits[1],
-		th->initial_limits[2]);
-
-	for (i = 0; i < 3; i++)
-		write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
-
-	write_both_fan_speed(th, -1);
-
-	thermostat = NULL;
-
-	kfree(th);
-
-	return 0;
-}
-
 static int read_fan_speed(struct thermostat *th, u8 addr)
 {
 	u8 tmp[2];
@@ -203,7 +141,7 @@ static int read_fan_speed(struct thermostat *th, u8 addr)
 static void write_both_fan_speed(struct thermostat *th, int speed)
 {
 	write_fan_speed(th, speed, 0);
-	if (therm_type == ADT7460)
+	if (th->type == ADT7460)
 		write_fan_speed(th, speed, 1);
 }
 
@@ -216,7 +154,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
 	else if (speed < -1) 
 		speed = 0;
 	
-	if (therm_type == ADT7467 && fan == 1)
+	if (th->type == ADT7467 && fan == 1)
 		return;
 	
 	if (th->last_speed[fan] != speed) {
@@ -239,7 +177,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
 		write_reg(th, FAN_SPD_SET[fan], speed);
 	} else {
 		/* back to automatic */
-		if(therm_type == ADT7460) {
+		if(th->type == ADT7460) {
 			manual = read_reg(th,
 				MANUAL_MODE[fan]) & (~MANUAL_MASK);
 			manual &= ~INVERT_MASK;
@@ -293,7 +231,7 @@ static void update_fans_speed (struct thermostat *th)
 	/* we don't care about local sensor, so we start at sensor 1 */
 	for (i = 1; i < 3; i++) {
 		int started = 0;
-		int fan_number = (therm_type == ADT7460 && i == 2);
+		int fan_number = (th->type == ADT7460 && i == 2);
 		int var = th->temps[i] - th->limits[i];
 
 		if (var > -1) {
@@ -370,116 +308,22 @@ static int monitor_task(void *arg)
 
 static void set_limit(struct thermostat *th, int i)
 {
-		/* Set sensor1 limit higher to avoid powerdowns */
-		th->limits[i] = default_limits_chip[i] + limit_adjust;
-		write_reg(th, LIMIT_REG[i], th->limits[i]);
+	/* Set sensor1 limit higher to avoid powerdowns */
+	th->limits[i] = default_limits_chip[i] + limit_adjust;
+	write_reg(th, LIMIT_REG[i], th->limits[i]);
 		
-		/* set our limits to normal */
-		th->limits[i] = default_limits_local[i] + limit_adjust;
+	/* set our limits to normal */
+	th->limits[i] = default_limits_local[i] + limit_adjust;
 }
 
-static int probe_thermostat(struct i2c_client *client,
-			    const struct i2c_device_id *id)
-{
-	struct thermostat* th;
-	int rc;
-	int i;
-
-	if (thermostat)
-		return 0;
-
-	th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
-	if (!th)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, th);
-	th->clt = client;
-
-	rc = read_reg(th, CONFIG_REG);
-	if (rc < 0) {
-		dev_err(&client->dev, "Thermostat failed to read config!\n");
-		kfree(th);
-		return -ENODEV;
-	}
-
-	/* force manual control to start the fan quieter */
-	if (fan_speed == -1)
-		fan_speed = 64;
-	
-	if(therm_type == ADT7460) {
-		printk(KERN_INFO "adt746x: ADT7460 initializing\n");
-		/* The 7460 needs to be started explicitly */
-		write_reg(th, CONFIG_REG, 1);
-	} else
-		printk(KERN_INFO "adt746x: ADT7467 initializing\n");
-
-	for (i = 0; i < 3; i++) {
-		th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
-		set_limit(th, i);
-	}
-
-	printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
-			 " to %d, %d, %d\n",
-			 th->initial_limits[0], th->initial_limits[1],
-			 th->initial_limits[2], th->limits[0], th->limits[1],
-			 th->limits[2]);
-
-	thermostat = th;
-
-	/* 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;
-	th->last_speed[1] = -2;
-	th->last_var[0] = -80;
-	th->last_var[1] = -80;
-
-	if (fan_speed != -1) {
-		/* manual mode, stop fans */
-		write_both_fan_speed(th, 0);
-	} else {
-		/* automatic mode */
-		write_both_fan_speed(th, -1);
-	}
-	
-	thread_therm = kthread_run(monitor_task, th, "kfand");
-
-	if (thread_therm == ERR_PTR(-ENOMEM)) {
-		printk(KERN_INFO "adt746x: Kthread creation failed\n");
-		thread_therm = NULL;
-		return -ENOMEM;
-	}
-
-	thermostat_create_files();
-
-	return 0;
+#define BUILD_SHOW_FUNC_INT(name, data)				\
+static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)	\
+{								\
+	struct thermostat *th = dev_get_drvdata(dev);		\
+	return sprintf(buf, "%d\n", data);			\
 }
 
-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
- * choice but implement a bunch of them...
- *
- * FIXME, it does now...
- */
-#define BUILD_SHOW_FUNC_INT(name, data)				\
+#define BUILD_SHOW_FUNC_INT_LITE(name, data)				\
 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)	\
 {								\
 	return sprintf(buf, "%d\n", data);			\
@@ -494,22 +338,24 @@ static ssize_t show_##name(struct device *dev, struct device_attribute *attr, ch
 #define BUILD_SHOW_FUNC_FAN(name, data)				\
 static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf)       \
 {								\
+	struct thermostat *th = dev_get_drvdata(dev);		\
 	return sprintf(buf, "%d (%d rpm)\n", 			\
-		thermostat->last_speed[data],			\
-		read_fan_speed(thermostat, FAN_SPEED[data])	\
+		th->last_speed[data],				\
+		read_fan_speed(th, FAN_SPEED[data])		\
 		);						\
 }
 
 #define BUILD_STORE_FUNC_DEG(name, data)			\
 static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
 {								\
+	struct thermostat *th = dev_get_drvdata(dev);		\
 	int val;						\
 	int i;							\
 	val = simple_strtol(buf, NULL, 10);			\
 	printk(KERN_INFO "Adjusting limits by %d degrees\n", val);	\
 	limit_adjust = val;					\
 	for (i=0; i < 3; i++)					\
-		set_limit(thermostat, i);			\
+		set_limit(th, i);				\
 	return n;						\
 }
 
@@ -525,20 +371,21 @@ static ssize_t store_##name(struct device *dev, struct device_attribute *attr, c
 	return n;						\
 }
 
-BUILD_SHOW_FUNC_INT(sensor1_temperature,	 (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_INT(sensor2_temperature,	 (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_INT(sensor1_limit,		 thermostat->limits[1])
-BUILD_SHOW_FUNC_INT(sensor2_limit,		 thermostat->limits[2])
+BUILD_SHOW_FUNC_INT(sensor1_temperature,	 (read_reg(th, TEMP_REG[1])))
+BUILD_SHOW_FUNC_INT(sensor2_temperature,	 (read_reg(th, TEMP_REG[2])))
+BUILD_SHOW_FUNC_INT(sensor1_limit,		 th->limits[1])
+BUILD_SHOW_FUNC_INT(sensor2_limit,		 th->limits[2])
 BUILD_SHOW_FUNC_STR(sensor1_location,		 sensor_location[1])
 BUILD_SHOW_FUNC_STR(sensor2_location,		 sensor_location[2])
 
-BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
+BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed)
+BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
+
 BUILD_SHOW_FUNC_FAN(sensor1_fan_speed,	 0)
 BUILD_SHOW_FUNC_FAN(sensor2_fan_speed,	 1)
 
-BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
-BUILD_SHOW_FUNC_INT(limit_adjust,	 limit_adjust)
-BUILD_STORE_FUNC_DEG(limit_adjust,	 thermostat)
+BUILD_SHOW_FUNC_INT_LITE(limit_adjust,	 limit_adjust)
+BUILD_STORE_FUNC_DEG(limit_adjust,	 th)
 		
 static DEVICE_ATTR(sensor1_temperature,	S_IRUGO,
 		   show_sensor1_temperature,NULL);
@@ -564,53 +411,77 @@ static DEVICE_ATTR(sensor2_fan_speed,	S_IRUGO,
 static DEVICE_ATTR(limit_adjust,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
 		   show_limit_adjust,	store_limit_adjust);
 
-
-static int __init
-thermostat_init(void)
+static void thermostat_create_files(struct thermostat *th)
 {
-	struct device_node* np;
-	const u32 *prop;
-	int i = 0, offset = 0;
+	struct device_node *np = th->clt->dev.of_node;
+	struct device *dev;
+	int err;
 
-	np = of_find_node_by_name(NULL, "fan");
-	if (!np)
-		return -ENODEV;
-	if (of_device_is_compatible(np, "adt7460"))
-		therm_type = ADT7460;
-	else if (of_device_is_compatible(np, "adt7467"))
-		therm_type = ADT7467;
-	else {
-		of_node_put(np);
-		return -ENODEV;
-	}
+	/* To maintain ABI compatibility with userspace, create
+	 * the old style platform driver and attach the attributes
+	 * to it here
+	 */
+	th->pdev = of_platform_device_create(np, "temperatures", NULL);
+	if (!th->pdev)
+		return;
+	dev = &th->pdev->dev;
+	dev_set_drvdata(dev, th);
+	err = device_create_file(dev, &dev_attr_sensor1_temperature);
+	err |= device_create_file(dev, &dev_attr_sensor2_temperature);
+	err |= device_create_file(dev, &dev_attr_sensor1_limit);
+	err |= device_create_file(dev, &dev_attr_sensor2_limit);
+	err |= device_create_file(dev, &dev_attr_sensor1_location);
+	err |= device_create_file(dev, &dev_attr_sensor2_location);
+	err |= device_create_file(dev, &dev_attr_limit_adjust);
+	err |= device_create_file(dev, &dev_attr_specified_fan_speed);
+	err |= device_create_file(dev, &dev_attr_sensor1_fan_speed);
+	if(th->type == ADT7460)
+		err |= device_create_file(dev, &dev_attr_sensor2_fan_speed);
+	if (err)
+		printk(KERN_WARNING
+			"Failed to create temperature attribute file(s).\n");
+}
 
-	prop = of_get_property(np, "hwsensor-params-version", NULL);
-	printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
-			 (*prop == 1)?"":"un");
-	if (*prop != 1) {
-		of_node_put(np);
-		return -ENODEV;
-	}
+static void thermostat_remove_files(struct thermostat *th)
+{
+	struct device *dev;
 
-	prop = of_get_property(np, "reg", NULL);
-	if (!prop) {
-		of_node_put(np);
-		return -ENODEV;
-	}
+	if (!th->pdev)
+		return;
+	dev = &th->pdev->dev;
+	device_remove_file(dev, &dev_attr_sensor1_temperature);
+	device_remove_file(dev, &dev_attr_sensor2_temperature);
+	device_remove_file(dev, &dev_attr_sensor1_limit);
+	device_remove_file(dev, &dev_attr_sensor2_limit);
+	device_remove_file(dev, &dev_attr_sensor1_location);
+	device_remove_file(dev, &dev_attr_sensor2_location);
+	device_remove_file(dev, &dev_attr_limit_adjust);
+	device_remove_file(dev, &dev_attr_specified_fan_speed);
+	device_remove_file(dev, &dev_attr_sensor1_fan_speed);	
+	if (th->type == ADT7460)
+		device_remove_file(dev, &dev_attr_sensor2_fan_speed);
+	of_device_unregister(th->pdev);
 
-	/* look for bus either by path or using "reg" */
-	if (strstr(np->full_name, "/i2c-bus@") != NULL) {
-		const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9);
-		therm_bus = tmp_bus[0]-'0';
-	} else {
-		therm_bus = ((*prop) >> 8) & 0x0f;
-	}
+}
 
-	therm_address = ((*prop) & 0xff) >> 1;
+static int probe_thermostat(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct device_node *np = client->dev.of_node;
+	struct thermostat* th;
+	const __be32 *prop;
+	int i, rc, vers, offset = 0;
 
-	printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, "
-			 "limit_adjust: %d, fan_speed: %d\n",
-			 therm_bus, therm_address, limit_adjust, fan_speed);
+	if (!np)
+		return -ENXIO;
+	prop = of_get_property(np, "hwsensor-params-version", NULL);
+	if (!prop)
+		return -ENXIO;
+	vers = be32_to_cpup(prop);
+	printk(KERN_INFO "adt746x: version %d (%ssupported)\n",
+	       vers, vers == 1 ? "" : "un");
+	if (vers != 1)
+		return -ENXIO;
 
 	if (of_get_property(np, "hwsensor-location", NULL)) {
 		for (i = 0; i < 3; i++) {
@@ -623,72 +494,129 @@ thermostat_init(void)
 			printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
 			offset += strlen(sensor_location[i]) + 1;
 		}
-	} else {
-		sensor_location[0] = "?";
-		sensor_location[1] = "?";
-		sensor_location[2] = "?";
 	}
 
-	of_dev = of_platform_device_create(np, "temperatures", NULL);
-	of_node_put(np);
+	th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
+	if (!th)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, th);
+	th->clt = client;
+	th->type = id->driver_data;
 
-	if (of_dev == NULL) {
-		printk(KERN_ERR "Can't register temperatures device !\n");
+	rc = read_reg(th, CONFIG_REG);
+	if (rc < 0) {
+		dev_err(&client->dev, "Thermostat failed to read config!\n");
+		kfree(th);
 		return -ENODEV;
 	}
 
-#ifndef CONFIG_I2C_POWERMAC
-	request_module("i2c-powermac");
-#endif
+	/* force manual control to start the fan quieter */
+	if (fan_speed == -1)
+		fan_speed = 64;
+	
+	if (th->type == ADT7460) {
+		printk(KERN_INFO "adt746x: ADT7460 initializing\n");
+		/* The 7460 needs to be started explicitly */
+		write_reg(th, CONFIG_REG, 1);
+	} else
+		printk(KERN_INFO "adt746x: ADT7467 initializing\n");
 
-	return i2c_add_driver(&thermostat_driver);
+	for (i = 0; i < 3; i++) {
+		th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
+		set_limit(th, i);
+	}
+
+	printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
+			 " to %d, %d, %d\n",
+			 th->initial_limits[0], th->initial_limits[1],
+			 th->initial_limits[2], th->limits[0], th->limits[1],
+			 th->limits[2]);
+
+	/* 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;
+	th->last_speed[1] = -2;
+	th->last_var[0] = -80;
+	th->last_var[1] = -80;
+
+	if (fan_speed != -1) {
+		/* manual mode, stop fans */
+		write_both_fan_speed(th, 0);
+	} else {
+		/* automatic mode */
+		write_both_fan_speed(th, -1);
+	}
+	
+	th->thread = kthread_run(monitor_task, th, "kfand");
+	if (th->thread == ERR_PTR(-ENOMEM)) {
+		printk(KERN_INFO "adt746x: Kthread creation failed\n");
+		th->thread = NULL;
+		return -ENOMEM;
+	}
+
+	thermostat_create_files(th);
+
+	return 0;
 }
 
-static void thermostat_create_files(void)
+static int remove_thermostat(struct i2c_client *client)
 {
-	int err;
+	struct thermostat *th = i2c_get_clientdata(client);
+	int i;
+	
+	thermostat_remove_files(th);
 
-	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)
-		err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
-	if (err)
-		printk(KERN_WARNING
-			"Failed to create temperature attribute file(s).\n");
+	if (th->thread != NULL)
+		kthread_stop(th->thread);
+
+	printk(KERN_INFO "adt746x: Putting max temperatures back from "
+			 "%d, %d, %d to %d, %d, %d\n",
+		th->limits[0], th->limits[1], th->limits[2],
+		th->initial_limits[0], th->initial_limits[1],
+		th->initial_limits[2]);
+
+	for (i = 0; i < 3; i++)
+		write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
+
+	write_both_fan_speed(th, -1);
+
+	kfree(th);
+
+	return 0;
 }
 
-static void thermostat_remove_files(void)
+static const struct i2c_device_id therm_adt746x_id[] = {
+	{ "MAC,adt7460", ADT7460 },
+	{ "MAC,adt7467", ADT7467 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, therm_adt746x_id);
+
+static struct i2c_driver thermostat_driver = {
+	.driver = {
+		.name	= "therm_adt746x",
+	},
+	.probe = probe_thermostat,
+	.remove = remove_thermostat,
+	.id_table = therm_adt746x_id,
+};
+
+static int __init thermostat_init(void)
 {
-	if (of_dev) {
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_location);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor2_location);
-		device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
-		device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-		device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-
-		if(therm_type == ADT7460)
-			device_remove_file(&of_dev->dev,
-					   &dev_attr_sensor2_fan_speed);
+#ifndef CONFIG_I2C_POWERMAC
+	request_module("i2c-powermac");
+#endif
 
-	}
+	return i2c_add_driver(&thermostat_driver);
 }
 
-static void __exit
-thermostat_exit(void)
+static void __exit thermostat_exit(void)
 {
 	i2c_del_driver(&thermostat_driver);
-	of_device_unregister(of_dev);
 }
 
 module_init(thermostat_init);
Signature · 1 line
1.7.9.5
#3 lore raw

PATCH 3/15 powerpc/pmac: Convert windfarm_lm75 to new i2c probing

In reply to Benjamin Herrenschmidt

This simplifies the driver to stop using the deprecated attach interface

---
 drivers/macintosh/windfarm_lm75_sensor.c |  124 ++++++++----------------------
 1 file changed, 30 insertions(+), 94 deletions(-)
drivers/macintosh/windfarm_lm75_sensor.c +30 -94
index 4d6a90a..4cc3f93 100644
@@ -23,7 +23,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 #undef DEBUG
 
@@ -36,8 +36,8 @@
 struct wf_lm75_sensor {
 	int			ds1775 : 1;
 	int			inited : 1;
-	struct 	i2c_client	*i2c;
-	struct 	wf_sensor	sens;
+	struct i2c_client	*i2c;
+	struct wf_sensor	sens;
 };
 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
 
@@ -90,40 +90,19 @@ static struct wf_sensor_ops wf_lm75_ops = {
 
 static int wf_lm75_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
-{
+{	
 	struct wf_lm75_sensor *lm;
-	int rc;
-
-	lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
-	if (lm == NULL)
-		return -ENODEV;
-
-	lm->inited = 0;
-	lm->ds1775 = id->driver_data;
-	lm->i2c = client;
-	lm->sens.name = client->dev.platform_data;
-	lm->sens.ops = &wf_lm75_ops;
-	i2c_set_clientdata(client, lm);
-
-	rc = wf_register_sensor(&lm->sens);
-	if (rc)
-		kfree(lm);
-
-	return rc;
-}
-
-static struct i2c_driver wf_lm75_driver;
-
-static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
-					     u8 addr, int ds1775,
-					     const char *loc)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-	char *name;
+	int rc, ds1775 = id->driver_data;
+	const char *name, *loc;
 
 	DBG("wf_lm75: creating  %s device at address 0x%02x\n",
-	    ds1775 ? "ds1775" : "lm75", addr);
+	    ds1775 ? "ds1775" : "lm75", client->addr);
+
+	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+	if (!loc) {
+		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+		return -ENXIO;
+	}
 
 	/* Usual rant about sensor names not beeing very consistent in
 	 * the device-tree, oh well ...
@@ -138,67 +117,24 @@ static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
 	else if (!strcmp(loc, "HD Temp"))
 		name = "hard-drive-temp";
 	else
-		goto fail;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = (addr >> 1) & 0x7f;
-	info.platform_data = name;
-	strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL) {
-		printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
-		       ds1775 ? "ds1775" : "lm75", name);
-		goto fail;
-	}
-
-	/*
-	 * 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, &wf_lm75_driver.clients);
-	return client;
- fail:
-	return NULL;
-}
-
-static int wf_lm75_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev;
-	struct pmac_i2c_bus *bus;
+		return -ENXIO;
+ 	
 
-	DBG("wf_lm75: adapter %s detected\n", adapter->name);
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
+	lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+	if (lm == NULL)
 		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
 
-	DBG("wf_lm75: bus found, looking for device...\n");
-
-	/* Now look for lm75(s) in there */
-	for (dev = NULL;
-	     (dev = of_get_next_child(busnode, dev)) != NULL;) {
-		const char *loc =
-			of_get_property(dev, "hwsensor-location", NULL);
-		u8 addr;
+	lm->inited = 0;
+	lm->ds1775 = ds1775;
+	lm->i2c = client;
+	lm->sens.name = (char *)name; /* XXX fix constness in structure */
+	lm->sens.ops = &wf_lm75_ops;
+	i2c_set_clientdata(client, lm);
 
-		/* We must re-match the adapter in order to properly check
-		 * the channel on multibus setups
-		 */
-		if (!pmac_i2c_match_adapter(dev, adapter))
-			continue;
-		addr = pmac_i2c_get_dev_addr(dev);
-		if (loc == NULL || addr == 0)
-			continue;
-		/* real lm75 */
-		if (of_device_is_compatible(dev, "lm75"))
-			wf_lm75_create(adapter, addr, 0, loc);
-		/* ds1775 (compatible, better resolution */
-		else if (of_device_is_compatible(dev, "ds1775"))
-			wf_lm75_create(adapter, addr, 1, loc);
-	}
-	return 0;
+	rc = wf_register_sensor(&lm->sens);
+	if (rc)
+		kfree(lm);
+	return rc;
 }
 
 static int wf_lm75_remove(struct i2c_client *client)
@@ -217,16 +153,16 @@ static int wf_lm75_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id wf_lm75_id[] = {
-	{ "wf_lm75", 0 },
-	{ "wf_ds1775", 1 },
+	{ "MAC,lm75", 0 },
+	{ "MAC,ds1775", 1 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
 
 static struct i2c_driver wf_lm75_driver = {
 	.driver = {
 		.name	= "wf_lm75",
 	},
-	.attach_adapter	= wf_lm75_attach,
 	.probe		= wf_lm75_probe,
 	.remove		= wf_lm75_remove,
 	.id_table	= wf_lm75_id,
Signature · 1 line
1.7.9.5
#4 lore raw

PATCH 4/15 powerpc/pmac: Convert windfarm_max6690 to new i2c probing

In reply to Benjamin Herrenschmidt

This simplifies the driver to stop using the deprecated attach interface

---
 drivers/macintosh/windfarm_max6690_sensor.c |  100 ++++++---------------------
 1 file changed, 21 insertions(+), 79 deletions(-)
drivers/macintosh/windfarm_max6690_sensor.c +21 -79
index 8204113..f4902f4 100644
@@ -16,7 +16,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 /* This currently only exports the external temperature sensor,
    since that's all the control loops need. */
@@ -64,9 +64,25 @@ static struct wf_sensor_ops wf_max6690_ops = {
 static int wf_max6690_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
+	const char *name, *loc;
 	struct wf_6690_sensor *max;
 	int rc;
 
+	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+	if (!loc) {
+		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+		return -ENXIO;
+	}
+
+	if (!strcmp(loc, "BACKSIDE"))
+		name = "backside-temp";
+	else if (!strcmp(loc, "NB Ambient"))
+		name = "north-bridge-temp";
+	else if (!strcmp(loc, "GPU Ambient"))
+		name = "gpu-temp";
+	else
+		return -ENXIO;
+
 	max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
 	if (max == NULL) {
 		printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
@@ -75,90 +91,16 @@ static int wf_max6690_probe(struct i2c_client *client,
 	}
 
 	max->i2c = client;
-	max->sens.name = client->dev.platform_data;
+	max->sens.name = (char *)name; /* XXX fix constness in structure */
 	max->sens.ops = &wf_max6690_ops;
 	i2c_set_clientdata(client, max);
 
 	rc = wf_register_sensor(&max->sens);
-	if (rc) {
+	if (rc)
 		kfree(max);
-	}
-
 	return rc;
 }
 
-static struct i2c_driver wf_max6690_driver;
-
-static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
-					    u8 addr, const char *loc)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-	char *name;
-
-	if (!strcmp(loc, "BACKSIDE"))
-		name = "backside-temp";
-	else if (!strcmp(loc, "NB Ambient"))
-		name = "north-bridge-temp";
-	else if (!strcmp(loc, "GPU Ambient"))
-		name = "gpu-temp";
-	else
-		goto fail;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = addr >> 1;
-	info.platform_data = name;
-	strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL) {
-		printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
-		goto fail;
-	}
-
-	/*
-	 * 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, &wf_max6690_driver.clients);
-	return client;
-
- fail:
-	return NULL;
-}
-
-static int wf_max6690_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-	const char *loc;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		u8 addr;
-
-		/* We must re-match the adapter in order to properly check
-		 * the channel on multibus setups
-		 */
-		if (!pmac_i2c_match_adapter(dev, adapter))
-			continue;
-		if (!of_device_is_compatible(dev, "max6690"))
-			continue;
-		addr = pmac_i2c_get_dev_addr(dev);
-		loc = of_get_property(dev, "hwsensor-location", NULL);
-		if (loc == NULL || addr == 0)
-			continue;
-		printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
-		wf_max6690_create(adapter, addr, loc);
-	}
-
-	return 0;
-}
-
 static int wf_max6690_remove(struct i2c_client *client)
 {
 	struct wf_6690_sensor *max = i2c_get_clientdata(client);
@@ -170,15 +112,15 @@ static int wf_max6690_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id wf_max6690_id[] = {
-	{ "wf_max6690", 0 },
+	{ "MAC,max6690", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
 
 static struct i2c_driver wf_max6690_driver = {
 	.driver = {
 		.name		= "wf_max6690",
 	},
-	.attach_adapter	= wf_max6690_attach,
 	.probe		= wf_max6690_probe,
 	.remove		= wf_max6690_remove,
 	.id_table	= wf_max6690_id,
Signature · 1 line
1.7.9.5
#5 lore raw

PATCH 5/15 powerpc/pmac: Convert windfarm_smu_sat to new i2c probing

In reply to Benjamin Herrenschmidt

This simplifies the driver to stop using the deprecated attach interface.

While at it we also implement teardown properly and fix the refcounting by using a kref.

---
 drivers/macintosh/windfarm_smu_sat.c |  126 +++++++++++++---------------------
 1 file changed, 47 insertions(+), 79 deletions(-)
drivers/macintosh/windfarm_smu_sat.c +47 -79
index 65a8ff3..72dfe19 100644
@@ -20,7 +20,7 @@
 
 #include "windfarm.h"
 
-#define VERSION "0.2"
+#define VERSION "1.0"
 
 #define DEBUG
 
@@ -34,11 +34,12 @@
 #define MAX_AGE		msecs_to_jiffies(800)
 
 struct wf_sat {
+	struct kref		ref;
 	int			nr;
-	atomic_t		refcnt;
 	struct mutex		mutex;
 	unsigned long		last_read; /* jiffies when cache last updated */
 	u8			cache[16];
+	struct list_head	sensors;
 	struct i2c_client	*i2c;
 	struct device_node	*node;
 };
@@ -46,11 +47,12 @@ struct wf_sat {
 static struct wf_sat *sats[2];
 
 struct wf_sat_sensor {
-	int		index;
-	int		index2;		/* used for power sensors */
-	int		shift;
-	struct wf_sat	*sat;
-	struct wf_sensor sens;
+	struct list_head	link;
+	int			index;
+	int			index2;		/* used for power sensors */
+	int			shift;
+	struct wf_sat		*sat;
+	struct wf_sensor 	sens;
 };
 
 #define wf_to_sat(c)	container_of(c, struct wf_sat_sensor, sens)
@@ -142,7 +144,7 @@ static int wf_sat_read_cache(struct wf_sat *sat)
 	return 0;
 }
 
-static int wf_sat_get(struct wf_sensor *sr, s32 *value)
+static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
 {
 	struct wf_sat_sensor *sens = wf_to_sat(sr);
 	struct wf_sat *sat = sens->sat;
@@ -175,58 +177,30 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
 	return err;
 }
 
-static void wf_sat_release(struct wf_sensor *sr)
+static void wf_sat_release(struct kref *ref)
+{
+	struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
+
+	if (sat->nr >= 0)
+		sats[sat->nr] = NULL;
+	kfree(sat);
+}
+
+static void wf_sat_sensor_release(struct wf_sensor *sr)
 {
 	struct wf_sat_sensor *sens = wf_to_sat(sr);
 	struct wf_sat *sat = sens->sat;
 
-	if (atomic_dec_and_test(&sat->refcnt)) {
-		if (sat->nr >= 0)
-			sats[sat->nr] = NULL;
-		kfree(sat);
-	}
 	kfree(sens);
+	kref_put(&sat->ref, wf_sat_release);
 }
 
 static struct wf_sensor_ops wf_sat_ops = {
-	.get_value	= wf_sat_get,
-	.release	= wf_sat_release,
+	.get_value	= wf_sat_sensor_get,
+	.release	= wf_sat_sensor_release,
 	.owner		= THIS_MODULE,
 };
 
-static struct i2c_driver wf_sat_driver;
-
-static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-	const u32 *reg;
-	u8 addr;
-
-	reg = of_get_property(dev, "reg", NULL);
-	if (reg == NULL)
-		return;
-	addr = *reg;
-	DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = (addr >> 1) & 0x7f;
-	info.platform_data = dev;
-	strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL) {
-		printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
-		return;
-	}
-
-	/*
-	 * 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, &wf_sat_driver.clients);
-}
-
 static int wf_sat_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -246,9 +220,10 @@ static int wf_sat_probe(struct i2c_client *client,
 		return -ENOMEM;
 	sat->nr = -1;
 	sat->node = of_node_get(dev);
-	atomic_set(&sat->refcnt, 0);
+	kref_init(&sat->ref);
 	mutex_init(&sat->mutex);
 	sat->i2c = client;
+	INIT_LIST_HEAD(&sat->sensors);
 	i2c_set_clientdata(client, sat);
 
 	vsens[0] = vsens[1] = -1;
@@ -310,14 +285,15 @@ static int wf_sat_probe(struct i2c_client *client,
 		sens->index2 = -1;
 		sens->shift = shift;
 		sens->sat = sat;
-		atomic_inc(&sat->refcnt);
 		sens->sens.ops = &wf_sat_ops;
 		sens->sens.name = (char *) (sens + 1);
 		snprintf(sens->sens.name, 16, "%s-%d", name, cpu);
 
-		if (wf_register_sensor(&sens->sens)) {
-			atomic_dec(&sat->refcnt);
+		if (wf_register_sensor(&sens->sens))
 			kfree(sens);
+		else {
+			list_add(&sens->link, &sat->sensors);
+			kref_get(&sat->ref);
 		}
 	}
 
@@ -336,14 +312,15 @@ static int wf_sat_probe(struct i2c_client *client,
 		sens->index2 = isens[core];
 		sens->shift = 0;
 		sens->sat = sat;
-		atomic_inc(&sat->refcnt);
 		sens->sens.ops = &wf_sat_ops;
 		sens->sens.name = (char *) (sens + 1);
 		snprintf(sens->sens.name, 16, "cpu-power-%d", cpu);
 
-		if (wf_register_sensor(&sens->sens)) {
-			atomic_dec(&sat->refcnt);
+		if (wf_register_sensor(&sens->sens))
 			kfree(sens);
+		else {
+			list_add(&sens->link, &sat->sensors);
+			kref_get(&sat->ref);
 		}
 	}
 
@@ -353,42 +330,35 @@ static int wf_sat_probe(struct i2c_client *client,
 	return 0;
 }
 
-static int wf_sat_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL)
-		if (of_device_is_compatible(dev, "smu-sat"))
-			wf_sat_create(adapter, dev);
-	return 0;
-}
-
 static int wf_sat_remove(struct i2c_client *client)
 {
 	struct wf_sat *sat = i2c_get_clientdata(client);
+	struct wf_sat_sensor *sens;
 
-	/* XXX TODO */
-
+	/* release sensors */
+	while(!list_empty(&sat->sensors)) {
+		sens = list_first_entry(&sat->sensors,
+					struct wf_sat_sensor, link);
+		list_del(&sens->link);
+		wf_unregister_sensor(&sens->sens);
+	}
 	sat->i2c = NULL;
+	i2c_set_clientdata(client, NULL);
+	kref_put(&sat->ref, wf_sat_release);
+
 	return 0;
 }
 
 static const struct i2c_device_id wf_sat_id[] = {
-	{ "wf_sat", 0 },
+	{ "MAC,smu-sat", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c, wf_sat_id);
 
 static struct i2c_driver wf_sat_driver = {
 	.driver = {
 		.name		= "wf_smu_sat",
 	},
-	.attach_adapter	= wf_sat_attach,
 	.probe		= wf_sat_probe,
 	.remove		= wf_sat_remove,
 	.id_table	= wf_sat_id,
@@ -399,15 +369,13 @@ static int __init sat_sensors_init(void)
 	return i2c_add_driver(&wf_sat_driver);
 }
 
-#if 0	/* uncomment when module_exit() below is uncommented */
 static void __exit sat_sensors_exit(void)
 {
 	i2c_del_driver(&wf_sat_driver);
 }
-#endif
 
 module_init(sat_sensors_init);
-/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
+module_exit(sat_sensors_exit);
 
 MODULE_AUTHOR("Paul Mackerras <[email protected]>");
 MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
Signature · 1 line
1.7.9.5
#6 lore raw

PATCH 6/15 powerpc/windfarm: const'ify and add "priv" field to controls & sensors

In reply to Benjamin Herrenschmidt

const'ify the sensor ops and name and add a void* for use by the control and sensor drivers to point back to their private data, avoiding the need to create a wrapper data structure per sensor or control instance.

---
 drivers/macintosh/windfarm.h |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/macintosh/windfarm.h +12 -11
index 7a2482c..3ef192a 100644
@@ -35,12 +35,12 @@ struct wf_control_ops {
 };
 
 struct wf_control {
-	struct list_head	link;
-	struct wf_control_ops	*ops;
-	char			*name;
-	int			type;
-	struct kref		ref;
-	struct device_attribute	attr;
+	struct list_head		link;
+	const struct wf_control_ops	*ops;
+	const char			*name;
+	int				type;
+	struct kref			ref;
+	struct device_attribute		attr;
 };
 
 #define WF_CONTROL_TYPE_GENERIC		0
@@ -85,11 +85,12 @@ struct wf_sensor_ops {
 };
 
 struct wf_sensor {
-	struct list_head	link;
-	struct wf_sensor_ops	*ops;
-	char			*name;
-	struct kref		ref;
-	struct device_attribute	attr;
+	struct list_head		link;
+	const struct wf_sensor_ops	*ops;
+	const char			*name;
+	struct kref			ref;
+	struct device_attribute		attr;
+	void				*priv;
 };
 
 /* Same lifetime rules as controls */
Signature · 1 line
1.7.9.5
#7 lore raw

PATCH 7/15 powerpc/pmac: Don't add_timer() twice

In reply to Benjamin Herrenschmidt

If the interrupt and the timeout happen roughly at the same time, we can get into a situation where the timer function is run while the interrupt has already been processed. In this case, the timer function might end up doing an add_timer on an already pending timer, causing a BUG_ON() to trigger.

Instead, just skip the whole timeout operation if we see that the timer is pending. The spinlock ensures that the only way that happens is if we already started a new operation and thus the timeout can be ignored.

---
 arch/powerpc/platforms/powermac/low_i2c.c |    9 +++++++++
 1 file changed, 9 insertions(+)
arch/powerpc/platforms/powermac/low_i2c.c +9 -0
index f991dbb..fc536f2 100644
@@ -366,11 +366,20 @@ static void kw_i2c_timeout(unsigned long data)
 	unsigned long flags;
 
 	spin_lock_irqsave(&host->lock, flags);
+
+	/*
+	 * If the timer is pending, that means we raced with the
+	 * irq, in which case we just return
+	 */
+	if (timer_pending(&host->timeout_timer))
+		goto skip;
+
 	kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
 	if (host->state != state_idle) {
 		host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
 		add_timer(&host->timeout_timer);
 	}
+ skip:
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
Signature · 1 line
1.7.9.5
#8 lore raw

PATCH 8/15 powerpc/windfarm: Remove spurrious sysfs_attr_init()

In reply to Benjamin Herrenschmidt

The windfarm core will do it, so this is a duplicate.

---
 drivers/macintosh/windfarm_smu_controls.c |    1 -
 1 file changed, 1 deletion(-)
drivers/macintosh/windfarm_smu_controls.c +0 -1
index 3c2be51..c155a54 100644
@@ -172,7 +172,6 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
 
 	fct->fan_type = pwm_fan;
 	fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
-	sysfs_attr_init(&fct->ctrl.attr.attr);
 
 	/* We use the name & location here the same way we do for SMU sensors,
 	 * see the comment in windfarm_smu_sensors.c. The locations are a bit
Signature · 1 line
1.7.9.5
#9 lore raw

PATCH 9/15 powerpc/windfarm: Improve display of fan speeds in sysfs

In reply to Benjamin Herrenschmidt

Controls registered as RPM and PWM fans are now displayed with the "RPM" or "%" suffix respectively to make it clearer to the user what the value actually means since the fan type isn't otherwise obvious.

---
 drivers/macintosh/windfarm_core.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/macintosh/windfarm_core.c +12 -1
index ce88979..ebafc25 100644
@@ -164,13 +164,24 @@ static ssize_t wf_show_control(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
 	struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
+	const char *typestr;
 	s32 val = 0;
 	int err;
 
 	err = ctrl->ops->get_value(ctrl, &val);
 	if (err < 0)
 		return err;
-	return sprintf(buf, "%d\n", val);
+	switch(ctrl->type) {
+	case WF_CONTROL_RPM_FAN:
+		typestr = " RPM";
+		break;
+	case WF_CONTROL_PWM_FAN:
+		typestr = " %";
+		break;
+	default:
+		typestr = "";
+	}
+	return sprintf(buf, "%d%s\n", val, typestr);
 }
 
 /* This is really only for debugging... */
Signature · 1 line
1.7.9.5
#10 lore raw

PATCH 10/15 powerpc/windfarm: Add useful accessors

In reply to Benjamin Herrenschmidt

Makes the code more readable

---
 drivers/macintosh/windfarm.h      |   25 +++++++++++++++++++++++++
 drivers/macintosh/windfarm_pm81.c |   25 ++++++++++++-------------
 drivers/macintosh/windfarm_pm91.c |   33 +++++++++++++++------------------
 3 files changed, 52 insertions(+), 31 deletions(-)
drivers/macintosh/windfarm.h +25 -0
index 3ef192a..a9e385e 100644
@@ -72,6 +72,26 @@ static inline int wf_control_set_min(struct wf_control *ct)
 	return ct->ops->set_value(ct, vmin);
 }
 
+static inline int wf_control_set(struct wf_control *ct, s32 val)
+{
+	return ct->ops->set_value(ct, val);
+}
+
+static inline int wf_control_get(struct wf_control *ct, s32 *val)
+{
+	return ct->ops->get_value(ct, val);
+}
+
+static inline s32 wf_control_get_min(struct wf_control *ct)
+{
+	return ct->ops->get_min(ct);
+}
+
+static inline s32 wf_control_get_max(struct wf_control *ct)
+{
+	return ct->ops->get_max(ct);
+}
+
 /*
  * Sensor objects
  */
@@ -100,6 +120,11 @@ extern struct wf_sensor * wf_find_sensor(const char *name);
 extern int wf_get_sensor(struct wf_sensor *sr);
 extern void wf_put_sensor(struct wf_sensor *sr);
 
+static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val)
+{
+	return sr->ops->get_value(sr, val);
+}
+
 /* For use by clients. Note that we are a bit racy here since
  * notifier_block doesn't have a module owner field. I may fix
  * it one day ...
drivers/macintosh/windfarm_pm81.c +12 -13
index fc13d0f..990c876 100644
@@ -302,13 +302,13 @@ static void wf_smu_create_sys_fans(void)
 	pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
 	pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
 	pid_param.itarget = param->itarget;
-	pid_param.min = fan_system->ops->get_min(fan_system);
-	pid_param.max = fan_system->ops->get_max(fan_system);
+	pid_param.min = wf_control_get_min(fan_system);
+	pid_param.max = wf_control_get_max(fan_system);
 	if (fan_hd) {
 		pid_param.min =
-			max(pid_param.min,fan_hd->ops->get_min(fan_hd));
+			max(pid_param.min, wf_control_get_min(fan_hd));
 		pid_param.max =
-			min(pid_param.max,fan_hd->ops->get_max(fan_hd));
+			min(pid_param.max, wf_control_get_max(fan_hd));
 	}
 	wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
 
@@ -337,7 +337,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
 	}
 	st->ticks = WF_SMU_SYS_FANS_INTERVAL;
 
-	rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+	rc = wf_sensor_get(sensor_hd_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
 		       rc);
@@ -373,7 +373,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
 	st->hd_setpoint = new_setpoint;
  readjust:
 	if (fan_system && wf_smu_failure_state == 0) {
-		rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
+		rc = wf_control_set(fan_system, st->sys_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: Sys fan error %d\n",
 			       rc);
@@ -381,7 +381,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
 		}
 	}
 	if (fan_hd && wf_smu_failure_state == 0) {
-		rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
+		rc = wf_control_set(fan_hd, st->hd_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: HD fan error %d\n",
 			       rc);
@@ -447,8 +447,8 @@ static void wf_smu_create_cpu_fans(void)
 	pid_param.ttarget = tmax - tdelta;
 	pid_param.pmaxadj = maxpow - powadj;
 
-	pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
-	pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+	pid_param.min = wf_control_get_min(fan_cpu_main);
+	pid_param.max = wf_control_get_max(fan_cpu_main);
 
 	wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
 
@@ -481,7 +481,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 	}
 	st->ticks = WF_SMU_CPU_FANS_INTERVAL;
 
-	rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+	rc = wf_sensor_get(sensor_cpu_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
 		       rc);
@@ -489,7 +489,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 		return;
 	}
 
-	rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+	rc = wf_sensor_get(sensor_cpu_power, &power);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
 		       rc);
@@ -525,8 +525,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 	st->cpu_setpoint = new_setpoint;
  readjust:
 	if (fan_cpu_main && wf_smu_failure_state == 0) {
-		rc = fan_cpu_main->ops->set_value(fan_cpu_main,
-						  st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU main fan"
 			       " error %d\n", rc);
drivers/macintosh/windfarm_pm91.c +15 -18
index a9430ed..e18002b 100644
@@ -192,8 +192,8 @@ static void wf_smu_create_cpu_fans(void)
 	pid_param.ttarget = tmax - tdelta;
 	pid_param.pmaxadj = maxpow - powadj;
 
-	pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
-	pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+	pid_param.min = wf_control_get_min(fan_cpu_main);
+	pid_param.max = wf_control_get_max(fan_cpu_main);
 
 	wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
 
@@ -226,7 +226,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 	}
 	st->ticks = WF_SMU_CPU_FANS_INTERVAL;
 
-	rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+	rc = wf_sensor_get(sensor_cpu_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
 		       rc);
@@ -234,7 +234,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 		return;
 	}
 
-	rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+	rc = wf_sensor_get(&sensor_cpu_power, &power);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
 		       rc);
@@ -261,8 +261,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 	st->cpu_setpoint = new_setpoint;
  readjust:
 	if (fan_cpu_main && wf_smu_failure_state == 0) {
-		rc = fan_cpu_main->ops->set_value(fan_cpu_main,
-						  st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU main fan"
 			       " error %d\n", rc);
@@ -270,8 +269,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 		}
 	}
 	if (fan_cpu_second && wf_smu_failure_state == 0) {
-		rc = fan_cpu_second->ops->set_value(fan_cpu_second,
-						    st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU second fan"
 			       " error %d\n", rc);
@@ -279,8 +277,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
 		}
 	}
 	if (fan_cpu_third && wf_smu_failure_state == 0) {
-		rc = fan_cpu_main->ops->set_value(fan_cpu_third,
-						  st->cpu_setpoint);
+		rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: CPU third fan"
 			       " error %d\n", rc);
@@ -312,8 +309,8 @@ static void wf_smu_create_drive_fans(void)
 
 	/* Fill PID params */
 	param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
-	param.min = fan_hd->ops->get_min(fan_hd);
-	param.max = fan_hd->ops->get_max(fan_hd);
+	param.min = wf_control_get_min(fan_hd);
+	param.max = wf_control_get_max(fan_hd);
 	wf_pid_init(&wf_smu_drive_fans->pid, &param);
 
 	DBG("wf: Drive Fan control initialized.\n");
@@ -338,7 +335,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
 	}
 	st->ticks = st->pid.param.interval;
 
-	rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+	rc = wf_sensor_get(sensor_hd_temp, &temp);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
 		       rc);
@@ -361,7 +358,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
 	st->setpoint = new_setpoint;
  readjust:
 	if (fan_hd && wf_smu_failure_state == 0) {
-		rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
+		rc = wf_control_set(fan_hd, st->setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: HD fan error %d\n",
 			       rc);
@@ -393,8 +390,8 @@ static void wf_smu_create_slots_fans(void)
 
 	/* Fill PID params */
 	param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
-	param.min = fan_slots->ops->get_min(fan_slots);
-	param.max = fan_slots->ops->get_max(fan_slots);
+	param.min = wf_control_get_min(fan_slots);
+	param.max = wf_control_get_max(fan_slots);
 	wf_pid_init(&wf_smu_slots_fans->pid, &param);
 
 	DBG("wf: Slots Fan control initialized.\n");
@@ -419,7 +416,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
 	}
 	st->ticks = st->pid.param.interval;
 
-	rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
+	rc = wf_sensor_get(sensor_slots_power, &power);
 	if (rc) {
 		printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
 		       rc);
@@ -444,7 +441,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
 	st->setpoint = new_setpoint;
  readjust:
 	if (fan_slots && wf_smu_failure_state == 0) {
-		rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
+		rc = wf_control_set(fan_slots, st->setpoint);
 		if (rc) {
 			printk(KERN_WARNING "windfarm: Slots fan error %d\n",
 			       rc);
Signature · 1 line
1.7.9.5
#11 lore raw

PATCH 11/15 powerpc/windfarm: Add ad7417 sensor

In reply to Benjamin Herrenschmidt

For user by the upcoming windfarm_pm72 and windfarm_rm31

---
 drivers/macintosh/windfarm_ad7417_sensor.c |  347 ++++++++++++++++++++++++++++
 1 file changed, 347 insertions(+)
 create mode 100644 drivers/macintosh/windfarm_ad7417_sensor.c
drivers/macintosh/windfarm_ad7417_sensor.c new file +347 -0
new file mode 100644
index 0000000..ac3f243
@@ -0,0 +1,347 @@
+/*
+ * Windfarm PowerMac thermal control. AD7417 sensors
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+struct wf_ad7417_priv {
+	struct kref		ref;
+	struct i2c_client	*i2c;
+	u8			config;
+	u8			cpu;
+	const struct mpu_data	*mpu;
+	struct wf_sensor	sensors[5];
+	struct mutex		lock;
+};
+
+static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
+{
+	struct wf_ad7417_priv *pv = sr->priv;
+	u8 buf[2];
+	s16 raw;
+	int rc;
+
+	*value = 0;
+	mutex_lock(&pv->lock);
+
+	/* Read temp register */
+	buf[0] = 0;
+	rc = i2c_master_send(pv->i2c, buf, 1);
+	if (rc < 0)
+		goto error;
+	rc = i2c_master_recv(pv->i2c, buf, 2);
+	if (rc < 0)
+		goto error;
+
+	/* Read a a 16-bit signed value */
+	raw = be16_to_cpup((__le16 *)buf);
+
+	/* Convert 8.8-bit to 16.16 fixed point */
+	*value = ((s32)raw) << 8;
+
+	mutex_unlock(&pv->lock);
+	return 0;
+
+error:
+	mutex_unlock(&pv->lock);
+	return -1;
+}
+
+/*
+ * Scaling factors for the AD7417 ADC converters (except
+ * for the CPU diode which is obtained from the EEPROM).
+ * Those values are obtained from the property list of
+ * the darwin driver
+ */
+#define ADC_12V_CURRENT_SCALE	0x0320	/* _AD2 */
+#define ADC_CPU_VOLTAGE_SCALE	0x00a0	/* _AD3 */
+#define ADC_CPU_CURRENT_SCALE	0x1f40	/* _AD4 */
+
+static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
+				  int chan, s32 raw, s32 *value)
+{
+	switch(chan) {
+	case 1: /* Diode */
+		*value = (raw * (s32)pv->mpu->mdiode +
+			((s32)pv->mpu->bdiode << 12)) >> 2;
+		break;
+	case 2: /* 12v current */
+		*value = raw * ADC_12V_CURRENT_SCALE;
+		break;
+	case 3: /* core voltage */
+		*value = raw * ADC_CPU_VOLTAGE_SCALE;
+		break;
+	case 4: /* core current */
+		*value = raw * ADC_CPU_CURRENT_SCALE;
+		break;
+	}
+}
+
+static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
+{
+	struct wf_ad7417_priv *pv = sr->priv;
+	int chan = sr - pv->sensors;
+	int i, rc;
+	u8 buf[2];
+	u16 raw;
+
+	*value = 0;
+	mutex_lock(&pv->lock);
+	for (i = 0; i < 10; i++) {
+		/* Set channel */
+		buf[0] = 1;
+		buf[1] = (pv->config & 0x1f) | (chan << 5);
+		rc = i2c_master_send(pv->i2c, buf, 2);
+		if (rc < 0)
+			goto error;
+
+		/* Wait for conversion */
+		msleep(1);
+
+		/* Switch to data register */
+		buf[0] = 4;
+		rc = i2c_master_send(pv->i2c, buf, 1);
+		if (rc < 0)
+			goto error;
+
+		/* Read result */
+		rc = i2c_master_recv(pv->i2c, buf, 2);
+		if (rc < 0)
+			goto error;
+
+		/* Read a a 16-bit signed value */
+		raw = be16_to_cpup((__le16 *)buf) >> 6;
+		wf_ad7417_adc_convert(pv, chan, raw, value);
+
+		dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
+			 " raw value: 0x%x, conv to: 0x%08x\n",
+			 chan, sr->name, raw, *value);
+
+		mutex_unlock(&pv->lock);
+		return 0;
+
+	error:
+		dev_dbg(&pv->i2c->dev,
+			  "Error reading ADC, try %d...\n", i);
+		if (i < 9)
+			msleep(10);
+	}
+	mutex_unlock(&pv->lock);
+	return -1;
+}
+
+static void wf_ad7417_release(struct kref *ref)
+{
+	struct wf_ad7417_priv *pv = container_of(ref,
+						 struct wf_ad7417_priv, ref);
+	kfree(pv);
+}
+
+static void wf_ad7417_sensor_release(struct wf_sensor *sr)
+{
+	struct wf_ad7417_priv *pv = sr->priv;
+
+	kfree(sr->name);
+	kref_put(&pv->ref, wf_ad7417_release);
+}
+
+static const struct wf_sensor_ops wf_ad7417_temp_ops = {
+	.get_value	= wf_ad7417_temp_get,
+	.release	= wf_ad7417_sensor_release,
+	.owner		= THIS_MODULE,
+};
+
+static const struct wf_sensor_ops wf_ad7417_adc_ops = {
+	.get_value	= wf_ad7417_adc_get,
+	.release	= wf_ad7417_sensor_release,
+	.owner		= THIS_MODULE,
+};
+
+static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
+					   int index, const char *name,
+					   const struct wf_sensor_ops *ops)
+{
+	pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
+	pv->sensors[index].priv = pv;
+	pv->sensors[index].ops = ops;
+	if (!wf_register_sensor(&pv->sensors[index]))
+		kref_get(&pv->ref);
+}
+
+static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
+{
+	int rc;
+	u8 buf[2];
+	u8 config = 0;
+
+	/*
+	 * Read ADC the configuration register and cache it. We
+	 * also make sure Config2 contains proper values, I've seen
+	 * cases where we got stale grabage in there, thus preventing
+	 * proper reading of conv. values
+	 */
+
+	/* Clear Config2 */
+	buf[0] = 5;
+	buf[1] = 0;
+	i2c_master_send(pv->i2c, buf, 2);
+
+	/* Read & cache Config1 */
+	buf[0] = 1;
+	rc = i2c_master_send(pv->i2c, buf, 1);
+	if (rc > 0) {
+		rc = i2c_master_recv(pv->i2c, buf, 1);
+		if (rc > 0) {
+			config = buf[0];
+
+			dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
+				config);
+
+			/* Disable shutdown mode */
+			config &= 0xfe;
+			buf[0] = 1;
+			buf[1] = config;
+			rc = i2c_master_send(pv->i2c, buf, 2);
+		}
+	}
+	if (rc <= 0)
+		dev_err(&pv->i2c->dev, "Error reading ADC config\n");
+
+	pv->config = config;
+}
+
+static int __devinit wf_ad7417_probe(struct i2c_client *client,
+				     const struct i2c_device_id *id)
+{
+	struct wf_ad7417_priv *pv;
+	const struct mpu_data *mpu;
+	const char *loc;
+	int cpu_nr;
+
+	loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+	if (!loc) {
+		dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * Identify which CPU we belong to by looking at the first entry
+	 * in the hwsensor-location list
+	 */
+	if (!strncmp(loc, "CPU A", 5))
+		cpu_nr = 0;
+	else if (!strncmp(loc, "CPU B", 5))
+		cpu_nr = 1;
+	else {
+		pr_err("wf_ad7417: Can't identify location %s\n", loc);
+		return -ENXIO;
+	}
+	mpu = wf_get_mpu(cpu_nr);
+	if (!mpu) {
+		dev_err(&client->dev, "Failed to retrieve MPU data\n");
+		return -ENXIO;
+	}
+
+	pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
+	if (pv == NULL)
+		return -ENODEV;
+
+	kref_init(&pv->ref);
+	mutex_init(&pv->lock);
+	pv->i2c = client;
+	pv->cpu = cpu_nr;
+	pv->mpu = mpu;
+	dev_set_drvdata(&client->dev, pv);
+
+	/* Initialize the chip */
+	wf_ad7417_init_chip(pv);
+
+	/*
+	 * We cannot rely on Apple device-tree giving us child
+	 * node with the names of the individual sensors so we
+	 * just hard code what we know about them
+	 */
+	wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
+	wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
+	wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
+	wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
+	wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
+
+	return 0;
+}
+
+static int __devexit wf_ad7417_remove(struct i2c_client *client)
+{
+	struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
+	int i;
+
+	/* Mark client detached */
+	pv->i2c = NULL;
+
+	/* Release sensor */
+	for (i = 0; i < 5; i++)
+		wf_unregister_sensor(&pv->sensors[i]);
+
+	kref_put(&pv->ref, wf_ad7417_release);
+
+	return 0;
+}
+
+static const struct i2c_device_id wf_ad7417_id[] = {
+	{ "MAC,ad7417", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
+
+static struct i2c_driver wf_ad7417_driver = {
+	.driver = {
+		.name	= "wf_ad7417",
+	},
+	.probe		= wf_ad7417_probe,
+	.remove		= wf_ad7417_remove,
+	.id_table	= wf_ad7417_id,
+};
+
+static int __devinit wf_ad7417_init(void)
+{
+	/* This is only supported on these machines */
+	if (!of_machine_is_compatible("PowerMac7,2") &&
+	    !of_machine_is_compatible("PowerMac7,3") &&
+	    !of_machine_is_compatible("RackMac3,1"))
+		return -ENODEV;
+
+	return i2c_add_driver(&wf_ad7417_driver);
+}
+
+static void __devexit wf_ad7417_exit(void)
+{
+	i2c_del_driver(&wf_ad7417_driver);
+}
+
+module_init(wf_ad7417_init);
+module_exit(wf_ad7417_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
+MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
+MODULE_LICENSE("GPL");
+
Signature · 1 line
1.7.9.5
#12 lore raw

PATCH 12/15 powerpc/windfarm: Add lm87 sensor

In reply to Benjamin Herrenschmidt

For use by the upcoming windfarm_rm31

---
 drivers/macintosh/windfarm_lm87_sensor.c |  201 ++++++++++++++++++++++++++++++
 1 file changed, 201 insertions(+)
 create mode 100644 drivers/macintosh/windfarm_lm87_sensor.c
drivers/macintosh/windfarm_lm87_sensor.c new file +201 -0
new file mode 100644
index 0000000..c071aab
@@ -0,0 +1,201 @@
+/*
+ * Windfarm PowerMac thermal control. LM87 sensor
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
+
+#include "windfarm.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while(0)
+#endif
+
+struct wf_lm87_sensor {
+	struct i2c_client	*i2c;
+	struct wf_sensor	sens;
+};
+#define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
+
+
+static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
+{
+	int rc, tries = 0;
+	u8 buf;
+
+	for (;;) {
+		/* Set address */
+		buf = (u8)reg;
+		rc = i2c_master_send(chip, &buf, 1);
+		if (rc <= 0)
+			goto error;
+		rc = i2c_master_recv(chip, &buf, 1);
+		if (rc <= 0)
+			goto error;
+		return (int)buf;
+	error:
+		DBG("wf_lm87: Error reading LM87, retrying...\n");
+		if (++tries > 10) {
+			printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
+			return -EIO;
+		}
+		msleep(10);
+	}
+}
+
+static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
+{
+	struct wf_lm87_sensor *lm = sr->priv;
+	s32 temp;
+
+	if (lm->i2c == NULL)
+		return -ENODEV;
+
+#define LM87_INT_TEMP		0x27
+
+	/* Read temperature register */
+	temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
+	if (temp < 0)
+		return temp;
+	*value = temp << 16;
+
+	return 0;
+}
+
+static void wf_lm87_release(struct wf_sensor *sr)
+{
+	struct wf_lm87_sensor *lm = wf_to_lm87(sr);
+
+	kfree(lm);
+}
+
+static struct wf_sensor_ops wf_lm87_ops = {
+	.get_value	= wf_lm87_get,
+	.release	= wf_lm87_release,
+	.owner		= THIS_MODULE,
+};
+
+static int wf_lm87_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{	
+	struct wf_lm87_sensor *lm;
+	const char *name = NULL, *loc;
+	struct device_node *np = NULL;
+	int rc;
+
+	/*
+	 * The lm87 contains a whole pile of sensors, additionally,
+	 * the Xserve G5 has several lm87's. However, for now we only
+	 * care about the internal temperature sensor
+	 */
+	while ((np = of_get_next_child(client->dev.of_node, np)) != NULL) {
+		if (strcmp(np->name, "int-temp"))
+			continue;
+		loc = of_get_property(np, "location", NULL);
+		if (!loc)
+			continue;
+		if (strstr(loc, "DIMM"))
+			name = "dimms-temp";
+		else if (strstr(loc, "Processors"))
+			name = "between-cpus-temp";
+		if (name) {
+			of_node_put(np);
+			break;
+		}
+	}
+	if (!name) {
+		pr_warning("wf_lm87: Unsupported sensor %s\n",
+			   client->dev.of_node->full_name);
+		return -ENODEV;
+	}
+
+	lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
+	if (lm == NULL)
+		return -ENODEV;
+
+	lm->i2c = client;
+	lm->sens.name = name;
+	lm->sens.ops = &wf_lm87_ops;
+	lm->sens.priv = lm;
+	i2c_set_clientdata(client, lm);
+
+	rc = wf_register_sensor(&lm->sens);
+	if (rc)
+		kfree(lm);
+	return rc;
+}
+
+static int wf_lm87_remove(struct i2c_client *client)
+{
+	struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
+
+	DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
+
+	/* Mark client detached */
+	lm->i2c = NULL;
+
+	/* release sensor */
+	wf_unregister_sensor(&lm->sens);
+
+	return 0;
+}
+
+static const struct i2c_device_id wf_lm87_id[] = {
+	{ "MAC,lm87cimt", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
+
+static struct i2c_driver wf_lm87_driver = {
+	.driver = {
+		.name	= "wf_lm87",
+	},
+	.probe		= wf_lm87_probe,
+	.remove		= wf_lm87_remove,
+	.id_table	= wf_lm87_id,
+};
+
+static int __init wf_lm87_sensor_init(void)
+{
+	/* We only support this on the Xserve */
+	if (!of_machine_is_compatible("RackMac3,1"))
+		return -ENODEV;
+
+	return i2c_add_driver(&wf_lm87_driver);
+}
+
+static void __exit wf_lm87_sensor_exit(void)
+{
+	i2c_del_driver(&wf_lm87_driver);
+}
+
+
+module_init(wf_lm87_sensor_init);
+module_exit(wf_lm87_sensor_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
+MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
Signature · 1 line
1.7.9.5
#13 lore raw

PATCH 13/15 powerpc/windfarm: Updates to lm75 and max6690 sensors

In reply to Benjamin Herrenschmidt

This allows those modules to load on PowerMac7,2 PowerMac7,3 and RackMac3,1 and add the sensor name conversion for those machines.

This will be used by the corresponding new windfarm modules for those machines.

Note that since therm_pm72 is linked first, it will still take priority on those i2c devices if built-in. If using modules it will depend which is loaded first, but you should avoid building therm_pm72 if you are using the new windfarm drivers

---
 drivers/macintosh/windfarm_lm75_sensor.c    |   11 ++++++-----
 drivers/macintosh/windfarm_max6690_sensor.c |   11 +++++------
 2 files changed, 11 insertions(+), 11 deletions(-)
drivers/macintosh/windfarm_lm75_sensor.c +6 -5
index 4cc3f93..b0c2d36 100644
@@ -116,6 +116,12 @@ static int wf_lm75_probe(struct i2c_client *client,
 		name = "optical-drive-temp";
 	else if (!strcmp(loc, "HD Temp"))
 		name = "hard-drive-temp";
+	else if (!strcmp(loc, "PCI SLOTS"))
+		name = "slots-temp";
+	else if (!strcmp(loc, "CPU A INLET"))
+		name = "cpu-inlet-temp-0";
+	else if (!strcmp(loc, "CPU B INLET"))
+		name = "cpu-inlet-temp-1";
 	else
 		return -ENXIO;
  	
@@ -170,11 +176,6 @@ static struct i2c_driver wf_lm75_driver = {
 
 static int __init wf_lm75_sensor_init(void)
 {
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
 	return i2c_add_driver(&wf_lm75_driver);
 }
 
drivers/macintosh/windfarm_max6690_sensor.c +5 -6
index f4902f4..371b058 100644
@@ -74,7 +74,11 @@ static int wf_max6690_probe(struct i2c_client *client,
 		return -ENXIO;
 	}
 
-	if (!strcmp(loc, "BACKSIDE"))
+	/*
+	 * We only expose the external temperature register for
+	 * now as this is all we need for our control loops
+	 */
+	if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))
 		name = "backside-temp";
 	else if (!strcmp(loc, "NB Ambient"))
 		name = "north-bridge-temp";
@@ -128,11 +132,6 @@ static struct i2c_driver wf_max6690_driver = {
 
 static int __init wf_max6690_sensor_init(void)
 {
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
 	return i2c_add_driver(&wf_max6690_driver);
 }
 
Signature · 1 line
1.7.9.5
#14 lore raw

PATCH 14/15 powerpc/windfarm: Add Fan Control Unit controls for G5s

In reply to Benjamin Herrenschmidt

The FCU operates the fans on the earlier generation G5 machines, this module will be used by upcoming windfarm drivers.

---
 drivers/macintosh/windfarm_fcu_controls.c |  617 +++++++++++++++++++++++++++++
 1 file changed, 617 insertions(+)
 create mode 100644 drivers/macintosh/windfarm_fcu_controls.c
drivers/macintosh/windfarm_fcu_controls.c new file +617 -0
new file mode 100644
index 0000000..871f8b4
@@ -0,0 +1,617 @@
+/*
+ * Windfarm PowerMac thermal control. FCU fan control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)	do { } while(0)
+#endif
+
+/*
+ * This option is "weird" :) Basically, if you define this to 1
+ * the control loop for the RPMs fans (not PWMs) will apply the
+ * correction factor obtained from the PID to the actual RPM
+ * speed read from the FCU.
+ *
+ * If you define the below constant to 0, then it will be
+ * applied to the setpoint RPM speed, that is basically the
+ * speed we proviously "asked" for.
+ *
+ * I'm not sure which of these Apple's algorithm is supposed
+ * to use
+ */
+#define RPM_PID_USE_ACTUAL_SPEED	1
+
+/* Default min/max for pumps */
+#define CPU_PUMP_OUTPUT_MAX		3200
+#define CPU_PUMP_OUTPUT_MIN		1250
+
+#define FCU_FAN_RPM		0
+#define FCU_FAN_PWM		1
+
+struct wf_fcu_priv {
+	struct kref		ref;
+	struct i2c_client	*i2c;
+	struct mutex		lock;
+	struct list_head	fan_list;
+	int			rpm_shift;
+};
+
+struct wf_fcu_fan {
+	struct list_head	link;
+	int			id;
+	s32			min, max, target;
+	struct wf_fcu_priv	*fcu_priv;
+	struct wf_control	ctrl;
+};
+
+static void wf_fcu_release(struct kref *ref)
+{
+	struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref);
+
+	kfree(pv);
+}
+
+static void wf_fcu_fan_release(struct wf_control *ct)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+
+	kref_put(&fan->fcu_priv->ref, wf_fcu_release);
+	kfree(fan);
+}
+
+static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg,
+			   unsigned char *buf, int nb)
+{
+	int tries, nr, nw;
+
+	mutex_lock(&pv->lock);
+
+	buf[0] = reg;
+	tries = 0;
+	for (;;) {
+		nw = i2c_master_send(pv->i2c, buf, 1);
+		if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+			break;
+		msleep(10);
+		++tries;
+	}
+	if (nw <= 0) {
+		pr_err("Failure writing address to FCU: %d", nw);
+		nr = nw;
+		goto bail;
+	}
+	tries = 0;
+	for (;;) {
+		nr = i2c_master_recv(pv->i2c, buf, nb);
+		if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
+			break;
+		msleep(10);
+		++tries;
+	}
+	if (nr <= 0)
+		pr_err("wf_fcu: Failure reading data from FCU: %d", nw);
+ bail:
+	mutex_unlock(&pv->lock);
+	return nr;
+}
+
+static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg,
+			    const unsigned char *ptr, int nb)
+{
+	int tries, nw;
+	unsigned char buf[16];
+
+	buf[0] = reg;
+	memcpy(buf+1, ptr, nb);
+	++nb;
+	tries = 0;
+	for (;;) {
+		nw = i2c_master_send(pv->i2c, buf, nb);
+		if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+			break;
+		msleep(10);
+		++tries;
+	}
+	if (nw < 0)
+		pr_err("wf_fcu: Failure writing to FCU: %d", nw);
+	return nw;
+}
+
+static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	int rc, shift = pv->rpm_shift;
+	unsigned char buf[2];
+
+	if (value < fan->min)
+		value = fan->min;
+	if (value > fan->max)
+		value = fan->max;
+
+	if (fan->target && fan->target == value)
+		return 0;
+	fan->target = value;
+
+	buf[0] = value >> (8 - shift);
+	buf[1] = value << shift;
+	rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2);
+	if (rc < 0)
+		return -EIO;
+	return 0;
+}
+
+static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	int rc, reg_base, shift = pv->rpm_shift;
+	unsigned char failure;
+	unsigned char active;
+	unsigned char buf[2];
+
+	rc = wf_fcu_read_reg(pv, 0xb, &failure, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((failure & (1 << fan->id)) != 0)
+		return -EFAULT;
+	rc = wf_fcu_read_reg(pv, 0xd, &active, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((active & (1 << fan->id)) == 0)
+		return -ENXIO;
+
+	/* Programmed value or real current speed */
+#if RPM_PID_USE_ACTUAL_SPEED
+	reg_base = 0x11;
+#else
+	reg_base = 0x10;
+#endif
+	rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2);
+	if (rc != 2)
+		return -EIO;
+
+	*value = (buf[0] << (8 - shift)) | buf[1] >> shift;
+
+	return 0;
+}
+
+static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	unsigned char buf[2];
+	int rc;
+
+	if (value < fan->min)
+		value = fan->min;
+	if (value > fan->max)
+		value = fan->max;
+
+	if (fan->target && fan->target == value)
+		return 0;
+	fan->target = value;
+
+	value = (value * 2559) / 1000;
+	buf[0] = value;
+	rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+	if (rc < 0)
+		return -EIO;
+	return 0;
+}
+
+static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	unsigned char failure;
+	unsigned char active;
+	unsigned char buf[2];
+	int rc;
+
+	rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((failure & (1 << fan->id)) != 0)
+		return -EFAULT;
+	rc = wf_fcu_read_reg(pv, 0x2d, &active, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((active & (1 << fan->id)) == 0)
+		return -ENXIO;
+
+	rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+	if (rc != 1)
+		return -EIO;
+
+	*value = (((s32)buf[0]) * 1000) / 2559;
+
+	return 0;
+}
+
+static s32 wf_fcu_fan_min(struct wf_control *ct)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+
+	return fan->min;
+}
+
+static s32 wf_fcu_fan_max(struct wf_control *ct)
+{
+	struct wf_fcu_fan *fan = ct->priv;
+
+	return fan->max;
+}
+
+static const struct wf_control_ops wf_fcu_fan_rpm_ops = {
+	.set_value	= wf_fcu_fan_set_rpm,
+	.get_value	= wf_fcu_fan_get_rpm,
+	.get_min	= wf_fcu_fan_min,
+	.get_max	= wf_fcu_fan_max,
+	.release	= wf_fcu_fan_release,
+	.owner		= THIS_MODULE,
+};
+
+static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
+	.set_value	= wf_fcu_fan_set_pwm,
+	.get_value	= wf_fcu_fan_get_pwm,
+	.get_min	= wf_fcu_fan_min,
+	.get_max	= wf_fcu_fan_max,
+	.release	= wf_fcu_fan_release,
+	.owner		= THIS_MODULE,
+};
+
+static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
+{
+	const struct mpu_data *mpu = wf_get_mpu(0);
+	u16 pump_min = 0, pump_max = 0xffff;
+	u16 tmp[4];
+
+	/* Try to fetch pumps min/max infos from eeprom */
+	if (mpu) {
+		memcpy(&tmp, mpu->processor_part_num, 8);
+		if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
+			pump_min = max(pump_min, tmp[0]);
+			pump_max = min(pump_max, tmp[1]);
+		}
+		if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
+			pump_min = max(pump_min, tmp[2]);
+			pump_max = min(pump_max, tmp[3]);
+		}
+	}
+
+	/* Double check the values, this _IS_ needed as the EEPROM on
+	 * some dual 2.5Ghz G5s seem, at least, to have both min & max
+	 * same to the same value ... (grrrr)
+	 */
+	if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
+		pump_min = CPU_PUMP_OUTPUT_MIN;
+		pump_max = CPU_PUMP_OUTPUT_MAX;
+	}
+
+	fan->min = pump_min;
+	fan->max = pump_max;
+
+	DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
+	    fan->ctrl.name, pump_min, pump_max);
+}
+
+static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
+{
+	struct wf_fcu_priv *pv = fan->fcu_priv;
+	const struct mpu_data *mpu0 = wf_get_mpu(0);
+	const struct mpu_data *mpu1 = wf_get_mpu(1);
+
+	/* Default */
+	fan->min = 2400 >> pv->rpm_shift;
+	fan->max = 56000 >> pv->rpm_shift;
+
+	/* CPU fans have min/max in MPU */
+	if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
+		fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+		fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+		goto bail;
+	}
+	if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
+		fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
+		fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan);
+		goto bail;
+	}
+	if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
+		fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
+		fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan);
+		goto bail;
+	}
+	if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
+		fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
+		fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan);
+		goto bail;
+	}
+	/* Rackmac variants, we just use mpu0 intake */
+	if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
+		fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+		fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+		goto bail;
+	}
+ bail:
+	DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
+	    fan->ctrl.name, fan->min, fan->max);
+}
+
+static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
+				     const char *name,
+				     int type, int id)
+{
+	struct wf_fcu_fan *fan;
+
+	fan = kzalloc(sizeof(*fan), GFP_KERNEL);
+	if (!fan)
+		return;
+	fan->fcu_priv = pv;
+	fan->id = id;
+	fan->ctrl.name = name;
+	fan->ctrl.priv = fan;
+
+	/* min/max is oddball but the code comes from
+	 * therm_pm72 which seems to work so ...
+	 */
+	if (type == FCU_FAN_RPM) {
+		if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
+			wf_fcu_get_pump_minmax(fan);
+		else
+			wf_fcu_get_rpmfan_minmax(fan);
+		fan->ctrl.type = WF_CONTROL_RPM_FAN;
+		fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
+	} else {
+		fan->min = 10;
+		fan->max = 100;
+		fan->ctrl.type = WF_CONTROL_PWM_FAN;
+		fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
+	}
+
+	if (wf_register_control(&fan->ctrl)) {
+		pr_err("wf_fcu: Failed to register fan %s\n", name);
+		kfree(fan);
+		return;
+	}
+	list_add(&fan->link, &pv->fan_list);
+	kref_get(&pv->ref);
+}
+
+static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
+{
+	/* Translation of device-tree location properties to
+	 * windfarm fan names
+	 */
+	static const struct {
+		const char *dt_name;	/* Device-tree name */
+		const char *ct_name;	/* Control name */
+	} loc_trans[] = {
+		{ "BACKSIDE",		"backside-fan",		},
+		{ "SYS CTRLR FAN",	"backside-fan",		},
+		{ "DRIVE BAY",		"drive-bay-fan",	},
+		{ "SLOT",		"slots-fan",		},
+		{ "PCI FAN",		"slots-fan",		},
+		{ "CPU A INTAKE",	"cpu-front-fan-0",	},
+		{ "CPU A EXHAUST",	"cpu-rear-fan-0",	},
+		{ "CPU B INTAKE",	"cpu-front-fan-1",	},
+		{ "CPU B EXHAUST",	"cpu-rear-fan-1",	},
+		{ "CPU A PUMP",		"cpu-pump-0",		},
+		{ "CPU B PUMP",		"cpu-pump-1",		},
+		{ "CPU A 1",		"cpu-fan-a-0",		},
+		{ "CPU A 2",		"cpu-fan-b-0",		},
+		{ "CPU A 3",		"cpu-fan-c-0",		},
+		{ "CPU B 1",		"cpu-fan-a-1",		},
+		{ "CPU B 2",		"cpu-fan-b-1",		},
+		{ "CPU B 3",		"cpu-fan-c-1",		},
+	};
+	struct device_node *np = NULL, *fcu = pv->i2c->dev.of_node;
+	int i;
+
+	DBG("Looking up FCU controls in device-tree...\n");
+
+	while ((np = of_get_next_child(fcu, np)) != NULL) {
+		int id, type = -1;
+		const char *loc;
+		const char *name;
+		const u32 *reg;
+
+		DBG(" control: %s, type: %s\n", np->name, np->type);
+
+		/* Detect control type */
+		if (!strcmp(np->type, "fan-rpm-control") ||
+		    !strcmp(np->type, "fan-rpm"))
+			type = FCU_FAN_RPM;
+		if (!strcmp(np->type, "fan-pwm-control") ||
+		    !strcmp(np->type, "fan-pwm"))
+			type = FCU_FAN_PWM;
+		/* Only care about fans for now */
+		if (type == -1)
+			continue;
+
+		/* Lookup for a matching location */
+		loc = of_get_property(np, "location", NULL);
+		reg = of_get_property(np, "reg", NULL);
+		if (loc == NULL || reg == NULL)
+			continue;
+		DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
+
+		for (i = 0; i < ARRAY_SIZE(loc_trans); i++) {
+			if (strncmp(loc, loc_trans[i].dt_name,
+				    strlen(loc_trans[i].dt_name)))
+				continue;
+			name = loc_trans[i].ct_name;
+
+			DBG(" location match, name: %s\n", name);
+
+			if (type == FCU_FAN_RPM)
+				id = ((*reg) - 0x10) / 2;
+			else
+				id = ((*reg) - 0x30) / 2;
+			if (id > 7) {
+				pr_warning("wf_fcu: Can't parse "
+				       "fan ID in device-tree for %s\n",
+					   np->full_name);
+				break;
+			}
+			wf_fcu_add_fan(pv, name, type, id);
+			break;
+		}
+	}
+}
+
+static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
+{
+	/* We only support the default fans for PowerMac7,2 */
+	if (!of_machine_is_compatible("PowerMac7,2"))
+		return;
+
+	wf_fcu_add_fan(pv, "backside-fan",	FCU_FAN_PWM, 1);
+	wf_fcu_add_fan(pv, "drive-bay-fan",	FCU_FAN_RPM, 2);
+	wf_fcu_add_fan(pv, "slots-fan",		FCU_FAN_PWM, 2);
+	wf_fcu_add_fan(pv, "cpu-front-fan-0",	FCU_FAN_RPM, 3);
+	wf_fcu_add_fan(pv, "cpu-rear-fan-0",	FCU_FAN_RPM, 4);
+	wf_fcu_add_fan(pv, "cpu-front-fan-1",	FCU_FAN_RPM, 5);
+	wf_fcu_add_fan(pv, "cpu-rear-fan-1",	FCU_FAN_RPM, 6);
+}
+
+static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
+{
+	unsigned char buf = 0xff;
+	int rc;
+
+	rc = wf_fcu_write_reg(pv, 0xe, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	rc = wf_fcu_read_reg(pv, 0, &buf, 1);
+	if (rc < 0)
+		return -EIO;
+	pv->rpm_shift = (buf == 1) ? 2 : 3;
+
+	pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n",
+		 pv->rpm_shift);
+
+	return 0;
+}
+
+static int __devinit wf_fcu_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	struct wf_fcu_priv *pv;
+
+	pv = kzalloc(sizeof(*pv), GFP_KERNEL);
+	if (!pv)
+		return -ENOMEM;
+
+	kref_init(&pv->ref);
+	mutex_init(&pv->lock);
+	INIT_LIST_HEAD(&pv->fan_list);
+	pv->i2c = client;
+
+	/*
+	 * First we must start the FCU which will query the
+	 * shift value to apply to RPMs
+	 */
+	if (wf_fcu_init_chip(pv)) {
+		pr_err("wf_fcu: Initialization failed !\n");
+		kfree(pv);
+		return -ENXIO;
+	}
+
+	/* First lookup fans in the device-tree */
+	wf_fcu_lookup_fans(pv);
+
+	/*
+	 * Older machines don't have the device-tree entries
+	 * we are looking for, just hard code the list
+	 */
+	if (list_empty(&pv->fan_list))
+		wf_fcu_default_fans(pv);
+
+	/* Still no fans ? FAIL */
+	if (list_empty(&pv->fan_list)) {
+		pr_err("wf_fcu: Failed to find fans for your machine\n");
+		kfree(pv);
+		return -ENODEV;
+	}
+
+	dev_set_drvdata(&client->dev, pv);
+
+	return 0;
+}
+
+static int __devexit wf_fcu_remove(struct i2c_client *client)
+{
+	struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
+	struct wf_fcu_fan *fan;
+
+	while (!list_empty(&pv->fan_list)) {
+		fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link);
+		list_del(&fan->link);
+		wf_unregister_control(&fan->ctrl);
+	}
+	kref_put(&pv->ref, wf_fcu_release);
+	return 0;
+}
+
+static const struct i2c_device_id wf_fcu_id[] = {
+	{ "MAC,fcu", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
+
+static struct i2c_driver wf_fcu_driver = {
+	.driver = {
+		.name	= "wf_fcu",
+	},
+	.probe		= wf_fcu_probe,
+	.remove		= wf_fcu_remove,
+	.id_table	= wf_fcu_id,
+};
+
+static int __init wf_fcu_init(void)
+{
+	return i2c_add_driver(&wf_fcu_driver);
+}
+
+static void __exit wf_fcu_exit(void)
+{
+	i2c_del_driver(&wf_fcu_driver);
+}
+
+
+module_init(wf_fcu_init);
+module_exit(wf_fcu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
+MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
Signature · 1 line
1.7.9.5
#15 lore raw

PATCH 15/15 powerpc/powermac: New windfarm driver for PowerMac G5 (AGP) and Xserve G5

In reply to Benjamin Herrenschmidt

This replaces the old therm_pm72 using the same windfarm infrastructure that was used for other PowerMac G5 models. The fan speeds and sensors should now be visible in the same location in sysfs.

The driver is split into separate core modules for PowerMac7,2 (and 7,3) and RackMac3,1, with a lot of the shared code now in the separate sensor and control modules.

---
 drivers/macintosh/Kconfig                  |   23 +-
 drivers/macintosh/Makefile                 |   14 +
 drivers/macintosh/windfarm.h               |    3 +-
 drivers/macintosh/windfarm_core.c          |   10 +-
 drivers/macintosh/windfarm_cpufreq_clamp.c |    6 -
 drivers/macintosh/windfarm_mpu.h           |  105 ++++
 drivers/macintosh/windfarm_pm72.c          |  872 ++++++++++++++++++++++++++++
 drivers/macintosh/windfarm_rm31.c          |  765 ++++++++++++++++++++++++
 8 files changed, 1783 insertions(+), 15 deletions(-)
 create mode 100644 drivers/macintosh/windfarm_mpu.h
 create mode 100644 drivers/macintosh/windfarm_pm72.c
 create mode 100644 drivers/macintosh/windfarm_rm31.c
drivers/macintosh/Kconfig +21 -2
index fa51af1..a555da6 100644
@@ -204,11 +204,14 @@ config THERM_ADT746X
 	  better fan behaviour by default, and some manual control.
 
 config THERM_PM72
-	tristate "Support for thermal management on PowerMac G5"
+	tristate "Support for thermal management on PowerMac G5 (AGP)"
 	depends on I2C && I2C_POWERMAC && PPC_PMAC64
+	default n
 	help
 	  This driver provides thermostat and fan control for the desktop
-	  G5 machines. 
+	  G5 machines.
+
+	  This is deprecated, use windfarm instead.
 
 config WINDFARM
 	tristate "New PowerMac thermal control infrastructure"
@@ -221,6 +224,22 @@ config WINDFARM_PM81
 	help
 	  This driver provides thermal control for the iMacG5
 
+config WINDFARM_PM72
+	tristate "Support for thermal management on PowerMac G5 (AGP)"
+	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+	select I2C_POWERMAC
+	help
+	  This driver provides thermal control for the PowerMac G5
+	  "AGP" variants (PowerMac 7,2 and 7,3)
+
+config WINDFARM_RM31
+	tristate "Support for thermal management on Xserve G5"
+	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+	select I2C_POWERMAC
+	help
+	  This driver provides thermal control for the Xserve G5
+	  (RackMac3,1)
+
 config WINDFARM_PM91
 	tristate "Support for thermal management on PowerMac9,1"
 	depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
drivers/macintosh/Makefile +14 -0
index 6652a6e..6753b65 100644
@@ -29,6 +29,20 @@ obj-$(CONFIG_THERM_PM72)	+= therm_pm72.o
 obj-$(CONFIG_THERM_WINDTUNNEL)	+= therm_windtunnel.o
 obj-$(CONFIG_THERM_ADT746X)	+= therm_adt746x.o
 obj-$(CONFIG_WINDFARM)	        += windfarm_core.o
+obj-$(CONFIG_WINDFARM_PM72)     += windfarm_fcu_controls.o \
+				   windfarm_ad7417_sensor.o \
+				   windfarm_lm75_sensor.o \
+				   windfarm_max6690_sensor.o \
+				   windfarm_pid.o \
+				   windfarm_cpufreq_clamp.o \
+				   windfarm_pm72.o
+obj-$(CONFIG_WINDFARM_RM31)     += windfarm_fcu_controls.o \
+				   windfarm_ad7417_sensor.o \
+				   windfarm_lm75_sensor.o \
+				   windfarm_lm87_sensor.o \
+				   windfarm_pid.o \
+				   windfarm_cpufreq_clamp.o \
+				   windfarm_rm31.o
 obj-$(CONFIG_WINDFARM_PM81)     += windfarm_smu_controls.o \
 				   windfarm_smu_sensors.o \
 				   windfarm_lm75_sensor.o windfarm_pid.o \
drivers/macintosh/windfarm.h +2 -1
index a9e385e..028cdac 100644
@@ -17,7 +17,7 @@
 #include <linux/device.h>
 
 /* Display a 16.16 fixed point value */
-#define FIX32TOPRINT(f)	((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+#define FIX32TOPRINT(f)	(((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
 
 /*
  * Control objects
@@ -41,6 +41,7 @@ struct wf_control {
 	int				type;
 	struct kref			ref;
 	struct device_attribute		attr;
+	void				*priv;
 };
 
 #define WF_CONTROL_TYPE_GENERIC		0
drivers/macintosh/windfarm_core.c +4 -6
index ebafc25..3ee198b 100644
@@ -169,8 +169,11 @@ static ssize_t wf_show_control(struct device *dev,
 	int err;
 
 	err = ctrl->ops->get_value(ctrl, &val);
-	if (err < 0)
+	if (err < 0) {
+		if (err == -EFAULT)
+			return sprintf(buf, "<HW FAULT>\n");
 		return err;
+	}
 	switch(ctrl->type) {
 	case WF_CONTROL_RPM_FAN:
 		typestr = " RPM";
@@ -481,11 +484,6 @@ static int __init windfarm_core_init(void)
 {
 	DBG("wf: core loaded\n");
 
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
 	platform_device_register(&wf_platform_device);
 	return 0;
 }
drivers/macintosh/windfarm_cpufreq_clamp.c +0 -6
index 1a77a7c..72d1fdf 100644
@@ -75,12 +75,6 @@ static int __init wf_cpufreq_clamp_init(void)
 {
 	struct wf_control *clamp;
 
-	/* Don't register on old machines that use therm_pm72 for now */
-	if (of_machine_is_compatible("PowerMac7,2") ||
-	    of_machine_is_compatible("PowerMac7,3") ||
-	    of_machine_is_compatible("RackMac3,1"))
-		return -ENODEV;
-
 	clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
 	if (clamp == NULL)
 		return -ENOMEM;
drivers/macintosh/windfarm_mpu.h new file +105 -0

105 lines not on this page · raw message

drivers/macintosh/windfarm_pm72.c new file +872 -0

872 lines not on this page · raw message

drivers/macintosh/windfarm_rm31.c new file +765 -0

765 lines not on this page · raw message

Signature · 1 line
1.7.9.5

A message that is not in the archive (sent off-list or not yet received): 1334823416-9138-2-git-send-email-benh__33169.052625499$1334826821$gmane$org@kernel.crashing.org

#17 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Review

Quoted 7 lines · Benjamin Herrenschmidt
(quoted diff) +7 -0
+		/* Make up a modalias. Note: we to _NOT_ want the standard
+		 * i2c drivers to match with any of our powermac stuff
+		 * unless they have been specifically modified to handle
+		 * it on a case by case basis. For example, for thermal
+		 * control, things like lm75 etc... shall match with their
+		 * corresponding windfarm drivers, _NOT_ the generic ones,
+		 * so we force a prefix of AAPL, onto the modalias to

s/AAPL,/MAC,/

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#18 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

In reply to a message not in the archive

That breaks the tas3004 driver (and most likely the pcm3052 driver as well), since it wants to create its own i2c device. I'm using the attached patch as a workaround (only tas3004 driver tested on iBook G4), but that needs to move the workarounds for the older systems that don't have proper compatible properties somewhere else, which I don't know where.

Andreas.

---
 sound/aoa/codecs/onyx.c |   75 ++------------------------------------------
 sound/aoa/codecs/tas.c  |   80 ++---------------------------------------------
 2 files changed, 6 insertions(+), 149 deletions(-)
sound/aoa/codecs/onyx.c +3 -72
index 270790d..4cedc69 100644
@@ -997,45 +997,10 @@ static void onyx_exit_codec(struct aoa_codec *codec)
 	onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
 }
 
-static int onyx_create(struct i2c_adapter *adapter,
-		       struct device_node *node,
-		       int addr)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "aoa_codec_onyx", I2C_NAME_SIZE);
-	info.addr = addr;
-	info.platform_data = node;
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-
-	/*
-	 * We know the driver is already loaded, so the device should be
-	 * already bound. If not it means binding failed, which suggests
-	 * the device doesn't really exist and should be deleted.
-	 * Ideally this would be replaced by better checks _before_
-	 * instantiating the device.
-	 */
-	if (!client->driver) {
-		i2c_unregister_device(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, &client->driver->clients);
-	return 0;
-}
-
 static int onyx_i2c_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
 {
-	struct device_node *node = client->dev.platform_data;
+	struct device_node *node = client->dev.of_node;
 	struct onyx *onyx;
 	u8 dummy;
 
@@ -1071,40 +1036,6 @@ static int onyx_i2c_probe(struct i2c_client *client,
 	return -ENODEV;
 }
 
-static int onyx_i2c_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (of_device_is_compatible(dev, "pcm3052")) {
-			const u32 *addr;
-			printk(KERN_DEBUG PFX "found pcm3052\n");
-			addr = of_get_property(dev, "reg", NULL);
-			if (!addr)
-				return -ENODEV;
-			return onyx_create(adapter, dev, (*addr)>>1);
-		}
-	}
-
-	/* if that didn't work, try desperate mode for older
-	 * machines that have stuff missing from the device tree */
-
-	if (!of_device_is_compatible(busnode, "k2-i2c"))
-		return -ENODEV;
-
-	printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
-	/* probe both possible addresses for the onyx chip */
-	if (onyx_create(adapter, NULL, 0x46) == 0)
-		return 0;
-	return onyx_create(adapter, NULL, 0x47);
-}
-
 static int onyx_i2c_remove(struct i2c_client *client)
 {
 	struct onyx *onyx = i2c_get_clientdata(client);
@@ -1117,16 +1048,16 @@ static int onyx_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id onyx_i2c_id[] = {
-	{ "aoa_codec_onyx", 0 },
+	{ "MAC,pcm3052", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c,onyx_i2c_id);
 
 static struct i2c_driver onyx_driver = {
 	.driver = {
 		.name = "aoa_codec_onyx",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = onyx_i2c_attach,
 	.probe = onyx_i2c_probe,
 	.remove = onyx_i2c_remove,
 	.id_table = onyx_i2c_id,
sound/aoa/codecs/tas.c +3 -77

109 lines not on this page · raw message

Signature · 7 lines
1.7.10.4


-- 
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#19 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 6 lines · Andreas Schwab

That breaks the tas3004 driver (and most likely the pcm3052 driver as well), since it wants to create its own i2c device. I'm using the attached patch as a workaround (only tas3004 driver tested on iBook G4), but that needs to move the workarounds for the older systems that don't have proper compatible properties somewhere else, which I don't know where.

Should we keep the tas_create method for those ? We could have some code in the aoa core file that calls those "fixups" to create missing devices...

Cheers,
Ben.

Quoted 238 lines

Andreas.

---
 sound/aoa/codecs/onyx.c |   75 ++------------------------------------------
 sound/aoa/codecs/tas.c  |   80 ++---------------------------------------------
 2 files changed, 6 insertions(+), 149 deletions(-)
sound/aoa/codecs/onyx.c +3 -72
index 270790d..4cedc69 100644
@@ -997,45 +997,10 @@ static void onyx_exit_codec(struct aoa_codec *codec)
 	onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
 }
 
-static int onyx_create(struct i2c_adapter *adapter,
-		       struct device_node *node,
-		       int addr)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "aoa_codec_onyx", I2C_NAME_SIZE);
-	info.addr = addr;
-	info.platform_data = node;
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-
-	/*
-	 * We know the driver is already loaded, so the device should be
-	 * already bound. If not it means binding failed, which suggests
-	 * the device doesn't really exist and should be deleted.
-	 * Ideally this would be replaced by better checks _before_
-	 * instantiating the device.
-	 */
-	if (!client->driver) {
-		i2c_unregister_device(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, &client->driver->clients);
-	return 0;
-}
-
 static int onyx_i2c_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
 {
-	struct device_node *node = client->dev.platform_data;
+	struct device_node *node = client->dev.of_node;
 	struct onyx *onyx;
 	u8 dummy;
 
@@ -1071,40 +1036,6 @@ static int onyx_i2c_probe(struct i2c_client *client,
 	return -ENODEV;
 }
 
-static int onyx_i2c_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (of_device_is_compatible(dev, "pcm3052")) {
-			const u32 *addr;
-			printk(KERN_DEBUG PFX "found pcm3052\n");
-			addr = of_get_property(dev, "reg", NULL);
-			if (!addr)
-				return -ENODEV;
-			return onyx_create(adapter, dev, (*addr)>>1);
-		}
-	}
-
-	/* if that didn't work, try desperate mode for older
-	 * machines that have stuff missing from the device tree */
-
-	if (!of_device_is_compatible(busnode, "k2-i2c"))
-		return -ENODEV;
-
-	printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
-	/* probe both possible addresses for the onyx chip */
-	if (onyx_create(adapter, NULL, 0x46) == 0)
-		return 0;
-	return onyx_create(adapter, NULL, 0x47);
-}
-
 static int onyx_i2c_remove(struct i2c_client *client)
 {
 	struct onyx *onyx = i2c_get_clientdata(client);
@@ -1117,16 +1048,16 @@ static int onyx_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id onyx_i2c_id[] = {
-	{ "aoa_codec_onyx", 0 },
+	{ "MAC,pcm3052", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c,onyx_i2c_id);
 
 static struct i2c_driver onyx_driver = {
 	.driver = {
 		.name = "aoa_codec_onyx",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = onyx_i2c_attach,
 	.probe = onyx_i2c_probe,
 	.remove = onyx_i2c_remove,
 	.id_table = onyx_i2c_id,
sound/aoa/codecs/tas.c +3 -77
index 8e63d1f..c491ae0 100644
@@ -883,43 +883,10 @@ static void tas_exit_codec(struct aoa_codec *codec)
 }
 
 
-static int tas_create(struct i2c_adapter *adapter,
-		       struct device_node *node,
-		       int addr)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "aoa_codec_tas", I2C_NAME_SIZE);
-	info.addr = addr;
-	info.platform_data = node;
-
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-	/*
-	 * We know the driver is already loaded, so the device should be
-	 * already bound. If not it means binding failed, and then there
-	 * is no point in keeping the device instantiated.
-	 */
-	if (!client->driver) {
-		i2c_unregister_device(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, &client->driver->clients);
-	return 0;
-}
-
 static int tas_i2c_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	struct device_node *node = client->dev.platform_data;
+	struct device_node *node = client->dev.of_node;
 	struct tas *tas;
 
 	tas = kzalloc(sizeof(struct tas), GFP_KERNEL);
@@ -953,47 +920,6 @@ static int tas_i2c_probe(struct i2c_client *client,
 	return -EINVAL;
 }
 
-static int tas_i2c_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (of_device_is_compatible(dev, "tas3004")) {
-			const u32 *addr;
-			printk(KERN_DEBUG PFX "found tas3004\n");
-			addr = of_get_property(dev, "reg", NULL);
-			if (!addr)
-				continue;
-			return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
-		}
-		/* older machines have no 'codec' node with a 'compatible'
-		 * property that says 'tas3004', they just have a 'deq'
-		 * node without any such property... */
-		if (strcmp(dev->name, "deq") == 0) {
-			const u32 *_addr;
-			u32 addr;
-			printk(KERN_DEBUG PFX "found 'deq' node\n");
-			_addr = of_get_property(dev, "i2c-address", NULL);
-			if (!_addr)
-				continue;
-			addr = ((*_addr) >> 1) & 0x7f;
-			/* now, if the address doesn't match any of the two
-			 * that a tas3004 can have, we cannot handle this.
-			 * I doubt it ever happens but hey. */
-			if (addr != 0x34 && addr != 0x35)
-				continue;
-			return tas_create(adapter, dev, addr);
-		}
-	}
-	return -ENODEV;
-}
-
 static int tas_i2c_remove(struct i2c_client *client)
 {
 	struct tas *tas = i2c_get_clientdata(client);
@@ -1011,16 +937,16 @@ static int tas_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tas_i2c_id[] = {
-	{ "aoa_codec_tas", 0 },
+	{ "MAC,tas3004", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c,tas_i2c_id);
 
 static struct i2c_driver tas_driver = {
 	.driver = {
 		.name = "aoa_codec_tas",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = tas_i2c_attach,
 	.probe = tas_i2c_probe,
 	.remove = tas_i2c_remove,
 	.id_table = tas_i2c_id,
Signature · 1 line
1.7.10.4
#20 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 3 lines · Benjamin Herrenschmidt

Should we keep the tas_create method for those ? We could have some code in the aoa core file that calls those "fixups" to create missing devices...

I'm not sure if the function is needed, if the device can be created in i2c_powermac_register_devices.

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#21 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 6 lines · Andreas Schwab
Quoted 3 lines

Should we keep the tas_create method for those ? We could have some code in the aoa core file that calls those "fixups" to create missing devices...

I'm not sure if the function is needed, if the device can be created in i2c_powermac_register_devices.

But it doesn't have a device-node ... does it ? Which machine is this btw ? Can you shoot me privately the device-tree ? That will help me figure out what exactly needs to be done.

Thanks !

Cheers,
Ben.

#22 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 10 lines · Benjamin Herrenschmidt
Quoted 6 lines · Andreas Schwab
Quoted 3 lines

Should we keep the tas_create method for those ? We could have some code in the aoa core file that calls those "fixups" to create missing devices...

I'm not sure if the function is needed, if the device can be created in i2c_powermac_register_devices.

But it doesn't have a device-node ... does it ? Which machine is this btw ?

It's a PowerMac G5. During booting I see this:

PowerMac i2c bus pmu 2 registered
PowerMac i2c bus pmu 1 registered
PowerMac i2c bus mac-io 0 registered
i2c i2c-5: i2c-powermac: modalias failure on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a i2c i2c-5: i2c-powermac: invalid reg on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/i2c-modem PowerMac i2c bus u3 1 registered
i2c i2c-6: i2c-powermac: modalias failure on /u3@0,f8000000/i2c@f8001000/cereal@1c0 PowerMac i2c bus u3 0 registered

The deq node has no compatible, perhaps the modalias can be constructed out of the name instead?

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#23 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 1 line · Andreas Schwab

It's a PowerMac G5. During booting I see this:

There's about half a dozen versions of those :-) I assume the older PowerMac7,2 ? It's the one that tends to have missing bits in the device-tree. In that case, I think we still have one of these working at work, I can have a look when I'm back.

Quoted 12 lines

PowerMac i2c bus pmu 2 registered
PowerMac i2c bus pmu 1 registered
PowerMac i2c bus mac-io 0 registered
i2c i2c-5: i2c-powermac: modalias failure
on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a i2c i2c-5: i2c-powermac: invalid reg
on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/i2c-modem PowerMac i2c bus u3 1 registered
i2c i2c-6: i2c-powermac: modalias failure
on /u3@0,f8000000/i2c@f8001000/cereal@1c0 PowerMac i2c bus u3 0 registered

Quoted 2 lines

The deq node has no compatible, perhaps the modalias can be constructed out of the name instead?

But where is the deq node ? Under i2c or under sound ? If not under i2c then we need to do something else entirely.

For modalias I'm thinking best might be to have the platform code create a platform device for sound and have aoa core match on that ;-)

Cheers,
Ben.

#24 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 5 lines · Benjamin Herrenschmidt
Quoted 1 line · Andreas Schwab

It's a PowerMac G5. During booting I see this:

There's about half a dozen versions of those :-) I assume the older PowerMac7,2 ?

Yes, that's right. Sorry for being imprecise.

Quoted 12 lines
Quoted 12 lines

PowerMac i2c bus pmu 2 registered
PowerMac i2c bus pmu 1 registered
PowerMac i2c bus mac-io 0 registered
i2c i2c-5: i2c-powermac: modalias failure
on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a i2c i2c-5: i2c-powermac: invalid reg
on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/i2c-modem PowerMac i2c bus u3 1 registered
i2c i2c-6: i2c-powermac: modalias failure
on /u3@0,f8000000/i2c@f8001000/cereal@1c0 PowerMac i2c bus u3 0 registered

Quoted 4 lines
Quoted 2 lines

The deq node has no compatible, perhaps the modalias can be constructed out of the name instead?

But where is the deq node ? Under i2c or under sound ?

It looks like /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a is under i2c.

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#25 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 22 lines · Andreas Schwab
Quoted 5 lines · Benjamin Herrenschmidt
Quoted 1 line · Andreas Schwab

It's a PowerMac G5. During booting I see this:

There's about half a dozen versions of those :-) I assume the older PowerMac7,2 ?

Yes, that's right. Sorry for being imprecise.

Quoted 12 lines
Quoted 12 lines

PowerMac i2c bus pmu 2 registered
PowerMac i2c bus pmu 1 registered
PowerMac i2c bus mac-io 0 registered
i2c i2c-5: i2c-powermac: modalias failure
on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a i2c i2c-5: i2c-powermac: invalid reg
on /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/i2c-modem PowerMac i2c bus u3 1 registered
i2c i2c-6: i2c-powermac: modalias failure
on /u3@0,f8000000/i2c@f8001000/cereal@1c0 PowerMac i2c bus u3 0 registered

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

The deq node has no compatible, perhaps the modalias can be constructed out of the name instead?

But where is the deq node ? Under i2c or under sound ?

It looks like /ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a is under i2c.

Ah, excellent, so a small quirk in i2c_powermac is the way to go then, we can detect it by name and hack up something. Either that or even better, in prom_init, we could add the missing property to the device-tree.

Any chance you can try that ? (Look at other examples of DT fixups in prom_init.c and don't forget the RELOC() around strings :-)

Cheers,
Ben.

#26 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

Quoted 4 lines · Benjamin Herrenschmidt

Ah, excellent, so a small quirk in i2c_powermac is the way to go then, we can detect it by name and hack up something. Either that or even better, in prom_init, we could add the missing property to the device-tree.

How does that look like? Though I'm not sure this is the right approach. Those models with the onyx chip that lack the pcm3052 compatible property apparently have no OF node at all to key off the workaround.

Andreas.

arch/powerpc/kernel/prom_init.c +34 -1
index 1b488e5..1b04159 100644
@@ -2554,7 +2554,7 @@ static void __init fixup_device_tree_chrp(void)
 #endif
 
 #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
-static void __init fixup_device_tree_pmac(void)
+static void __init fixup_device_tree_pmac_u3_i2c(void)
 {
 	phandle u3, i2c, mpic;
 	u32 u3_rev;
@@ -2593,6 +2593,39 @@ static void __init fixup_device_tree_pmac(void)
 	prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent",
 		     &parent, sizeof(parent));
 }
+
+static void __init fixup_device_tree_pmac_deq(void)
+{
+	phandle deq;
+	u32 i2c_address;
+
+	/*
+	 * On older G5s the tas3004 is described by a deq node missing a
+	 * compatible definition, instead of a codec node with a
+	 * tas3004,code compatible property. Fix that up here.
+	 */
+	deq = call_prom("finddevice", 1, 1, ADDR("/ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a"));
+	if (!PHANDLE_VALID(deq))
+		return;
+	/* Check for proper i2c-address. */
+	if (prom_getprop(deq, "i2c-address", &i2c_address, sizeof(i2c_address)) == PROM_ERROR)
+		return;
+	i2c_address = (i2c_address >> 1) & 0x7f;
+	if (i2c_address != 0x34 && i2c_address != 0x35)
+		return;
+
+	prom_printf("fixing up missing compatible for deq node...\n");
+
+	prom_setprop (deq, "/ht@0,f2000000/pci@1/mac-io@7/i2c@18000/deq@6a",
+		      "compatible", &RELOC("tas3004\0codec\0"),
+		      sizeof("tas3004\0codec\0"));
+}
+
+static void __init fixup_device_tree_pmac(void)
+{
+	fixup_device_tree_pmac_u3_i2c();
+	fixup_device_tree_pmac_deq();
+}
 #else
 #define fixup_device_tree_pmac()
 #endif
Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#27 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

In reply to Benjamin Herrenschmidt
Quoted 7 lines · Benjamin Herrenschmidt

Ah, excellent, so a small quirk in i2c_powermac is the way to go then, we can detect it by name and hack up something. Either that or even better, in prom_init, we could add the missing property to the device-tree.

Any chance you can try that ? (Look at other examples of DT fixups in prom_init.c and don't forget the RELOC() around strings :-)

Ok, don't bother. I've been looking into it more closely and I think the best solution here is actually self contained in i2c-powermac.

I found a couple more device-tree oddities in older machines that I'm adding workarounds for as well. I'll send a couple of patches later today including your original one.

Cheers,
Ben.

#28 lore raw

Re: [PATCH 01/15] i2c/powermac: Register i2c devices from device-tree

In reply to Andreas Schwab
Quoted 8 lines · Andreas Schwab

That breaks the tas3004 driver (and most likely the pcm3052 driver as well), since it wants to create its own i2c device. I'm using the attached patch as a workaround (only tas3004 driver tested on iBook G4), but that needs to move the workarounds for the older systems that don't have proper compatible properties somewhere else, which I don't know where.

Andreas.

Can I put your signed-off-by: on that one ?

Cheers,
Ben.

Quoted 236 lines
---
 sound/aoa/codecs/onyx.c |   75 ++------------------------------------------
 sound/aoa/codecs/tas.c  |   80 ++---------------------------------------------
 2 files changed, 6 insertions(+), 149 deletions(-)
sound/aoa/codecs/onyx.c +3 -72
index 270790d..4cedc69 100644
@@ -997,45 +997,10 @@ static void onyx_exit_codec(struct aoa_codec *codec)
 	onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
 }
 
-static int onyx_create(struct i2c_adapter *adapter,
-		       struct device_node *node,
-		       int addr)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "aoa_codec_onyx", I2C_NAME_SIZE);
-	info.addr = addr;
-	info.platform_data = node;
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-
-	/*
-	 * We know the driver is already loaded, so the device should be
-	 * already bound. If not it means binding failed, which suggests
-	 * the device doesn't really exist and should be deleted.
-	 * Ideally this would be replaced by better checks _before_
-	 * instantiating the device.
-	 */
-	if (!client->driver) {
-		i2c_unregister_device(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, &client->driver->clients);
-	return 0;
-}
-
 static int onyx_i2c_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
 {
-	struct device_node *node = client->dev.platform_data;
+	struct device_node *node = client->dev.of_node;
 	struct onyx *onyx;
 	u8 dummy;
 
@@ -1071,40 +1036,6 @@ static int onyx_i2c_probe(struct i2c_client *client,
 	return -ENODEV;
 }
 
-static int onyx_i2c_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (of_device_is_compatible(dev, "pcm3052")) {
-			const u32 *addr;
-			printk(KERN_DEBUG PFX "found pcm3052\n");
-			addr = of_get_property(dev, "reg", NULL);
-			if (!addr)
-				return -ENODEV;
-			return onyx_create(adapter, dev, (*addr)>>1);
-		}
-	}
-
-	/* if that didn't work, try desperate mode for older
-	 * machines that have stuff missing from the device tree */
-
-	if (!of_device_is_compatible(busnode, "k2-i2c"))
-		return -ENODEV;
-
-	printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
-	/* probe both possible addresses for the onyx chip */
-	if (onyx_create(adapter, NULL, 0x46) == 0)
-		return 0;
-	return onyx_create(adapter, NULL, 0x47);
-}
-
 static int onyx_i2c_remove(struct i2c_client *client)
 {
 	struct onyx *onyx = i2c_get_clientdata(client);
@@ -1117,16 +1048,16 @@ static int onyx_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id onyx_i2c_id[] = {
-	{ "aoa_codec_onyx", 0 },
+	{ "MAC,pcm3052", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c,onyx_i2c_id);
 
 static struct i2c_driver onyx_driver = {
 	.driver = {
 		.name = "aoa_codec_onyx",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = onyx_i2c_attach,
 	.probe = onyx_i2c_probe,
 	.remove = onyx_i2c_remove,
 	.id_table = onyx_i2c_id,
sound/aoa/codecs/tas.c +3 -77
index 8e63d1f..c491ae0 100644
@@ -883,43 +883,10 @@ static void tas_exit_codec(struct aoa_codec *codec)
 }
 
 
-static int tas_create(struct i2c_adapter *adapter,
-		       struct device_node *node,
-		       int addr)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "aoa_codec_tas", I2C_NAME_SIZE);
-	info.addr = addr;
-	info.platform_data = node;
-
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-	/*
-	 * We know the driver is already loaded, so the device should be
-	 * already bound. If not it means binding failed, and then there
-	 * is no point in keeping the device instantiated.
-	 */
-	if (!client->driver) {
-		i2c_unregister_device(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, &client->driver->clients);
-	return 0;
-}
-
 static int tas_i2c_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	struct device_node *node = client->dev.platform_data;
+	struct device_node *node = client->dev.of_node;
 	struct tas *tas;
 
 	tas = kzalloc(sizeof(struct tas), GFP_KERNEL);
@@ -953,47 +920,6 @@ static int tas_i2c_probe(struct i2c_client *client,
 	return -EINVAL;
 }
 
-static int tas_i2c_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (of_device_is_compatible(dev, "tas3004")) {
-			const u32 *addr;
-			printk(KERN_DEBUG PFX "found tas3004\n");
-			addr = of_get_property(dev, "reg", NULL);
-			if (!addr)
-				continue;
-			return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
-		}
-		/* older machines have no 'codec' node with a 'compatible'
-		 * property that says 'tas3004', they just have a 'deq'
-		 * node without any such property... */
-		if (strcmp(dev->name, "deq") == 0) {
-			const u32 *_addr;
-			u32 addr;
-			printk(KERN_DEBUG PFX "found 'deq' node\n");
-			_addr = of_get_property(dev, "i2c-address", NULL);
-			if (!_addr)
-				continue;
-			addr = ((*_addr) >> 1) & 0x7f;
-			/* now, if the address doesn't match any of the two
-			 * that a tas3004 can have, we cannot handle this.
-			 * I doubt it ever happens but hey. */
-			if (addr != 0x34 && addr != 0x35)
-				continue;
-			return tas_create(adapter, dev, addr);
-		}
-	}
-	return -ENODEV;
-}
-
 static int tas_i2c_remove(struct i2c_client *client)
 {
 	struct tas *tas = i2c_get_clientdata(client);
@@ -1011,16 +937,16 @@ static int tas_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id tas_i2c_id[] = {
-	{ "aoa_codec_tas", 0 },
+	{ "MAC,tas3004", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c,tas_i2c_id);
 
 static struct i2c_driver tas_driver = {
 	.driver = {
 		.name = "aoa_codec_tas",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = tas_i2c_attach,
 	.probe = tas_i2c_probe,
 	.remove = tas_i2c_remove,
 	.id_table = tas_i2c_id,
Signature · 1 line
1.7.10.4
#29 lore raw

PATCH 1/1 sound/aoa: remove i2c attach_adapter method

Since i2c-powermac now creates all i2c devices on its own, remove the attach_adapter methods from the TAS and Onyx drivers, and adjust the module aliases to match the names used by i2c-powermac.

---
 sound/aoa/codecs/onyx.c | 75 ++--------------------------------------------
 sound/aoa/codecs/tas.c  | 80 ++-----------------------------------------------
 2 files changed, 6 insertions(+), 149 deletions(-)
sound/aoa/codecs/onyx.c +3 -72
index 270790d..4cedc69 100644
@@ -997,45 +997,10 @@ static void onyx_exit_codec(struct aoa_codec *codec)
 	onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
 }
 
-static int onyx_create(struct i2c_adapter *adapter,
-		       struct device_node *node,
-		       int addr)
-{
-	struct i2c_board_info info;
-	struct i2c_client *client;
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "aoa_codec_onyx", I2C_NAME_SIZE);
-	info.addr = addr;
-	info.platform_data = node;
-	client = i2c_new_device(adapter, &info);
-	if (!client)
-		return -ENODEV;
-
-	/*
-	 * We know the driver is already loaded, so the device should be
-	 * already bound. If not it means binding failed, which suggests
-	 * the device doesn't really exist and should be deleted.
-	 * Ideally this would be replaced by better checks _before_
-	 * instantiating the device.
-	 */
-	if (!client->driver) {
-		i2c_unregister_device(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, &client->driver->clients);
-	return 0;
-}
-
 static int onyx_i2c_probe(struct i2c_client *client,
 			  const struct i2c_device_id *id)
 {
-	struct device_node *node = client->dev.platform_data;
+	struct device_node *node = client->dev.of_node;
 	struct onyx *onyx;
 	u8 dummy;
 
@@ -1071,40 +1036,6 @@ static int onyx_i2c_probe(struct i2c_client *client,
 	return -ENODEV;
 }
 
-static int onyx_i2c_attach(struct i2c_adapter *adapter)
-{
-	struct device_node *busnode, *dev = NULL;
-	struct pmac_i2c_bus *bus;
-
-	bus = pmac_i2c_adapter_to_bus(adapter);
-	if (bus == NULL)
-		return -ENODEV;
-	busnode = pmac_i2c_get_bus_node(bus);
-
-	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (of_device_is_compatible(dev, "pcm3052")) {
-			const u32 *addr;
-			printk(KERN_DEBUG PFX "found pcm3052\n");
-			addr = of_get_property(dev, "reg", NULL);
-			if (!addr)
-				return -ENODEV;
-			return onyx_create(adapter, dev, (*addr)>>1);
-		}
-	}
-
-	/* if that didn't work, try desperate mode for older
-	 * machines that have stuff missing from the device tree */
-
-	if (!of_device_is_compatible(busnode, "k2-i2c"))
-		return -ENODEV;
-
-	printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
-	/* probe both possible addresses for the onyx chip */
-	if (onyx_create(adapter, NULL, 0x46) == 0)
-		return 0;
-	return onyx_create(adapter, NULL, 0x47);
-}
-
 static int onyx_i2c_remove(struct i2c_client *client)
 {
 	struct onyx *onyx = i2c_get_clientdata(client);
@@ -1117,16 +1048,16 @@ static int onyx_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id onyx_i2c_id[] = {
-	{ "aoa_codec_onyx", 0 },
+	{ "MAC,pcm3052", 0 },
 	{ }
 };
+MODULE_DEVICE_TABLE(i2c,onyx_i2c_id);
 
 static struct i2c_driver onyx_driver = {
 	.driver = {
 		.name = "aoa_codec_onyx",
 		.owner = THIS_MODULE,
 	},
-	.attach_adapter = onyx_i2c_attach,
 	.probe = onyx_i2c_probe,
 	.remove = onyx_i2c_remove,
 	.id_table = onyx_i2c_id,
sound/aoa/codecs/tas.c +3 -77

109 lines not on this page · raw message

Signature · 9 lines
1.7.11


Andreas.

-- 
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#30 lore raw
In reply to Benjamin Herrenschmidt
Quoted 14 lines · Benjamin Herrenschmidt

The goal of this series is to convert a bulk of PowerMac i2c drivers to the new "proper" i2c driver registration model. This series is not complete in that there are still a few drivers to do but it goes through the bulk of thermal control and some of the nastiest.

The biggest change is that windfarm is ported to generally use the new model, and I've written a new set of windfarm modules to take over from the old therm_pm72 (which was mostly unfixable) on the PowerMac G5 AGP and Xserve G5 machines.

This had a bit of testing on a couple of PowerMac G5 AGP variants but none at all on Xserve G5 since the one I have is unfortunately dead.

Quoted 6 lines

If you want to help me test this, don't forget to disable therm_pm72, and instead load windfarm_pm72 or windfarm_rm31 depending on your machine (you can load or build-in the whole lot as well). As usual windfarm don't properly auto-load yet, I still need to fix that.

So please test ! Especially if you have an XServe G5

Benjamin, thanks a lot for doing this! These drivers were the last ones blocking the removal of the legacy binding model in i2c-core. Testers are very welcome. The earliest we can get these changes upstream, the better.

Christian, can you please test this series? I'm sure Benjamin can send the patches to you directly if needed.

Signature · 1 line
Jean Delvare
#31 lore raw
Quoted 22 lines · Jean Delvare
Quoted 14 lines · Benjamin Herrenschmidt

The goal of this series is to convert a bulk of PowerMac i2c drivers to the new "proper" i2c driver registration model. This series is not complete in that there are still a few drivers to do but it goes through the bulk of thermal control and some of the nastiest.

The biggest change is that windfarm is ported to generally use the new model, and I've written a new set of windfarm modules to take over from the old therm_pm72 (which was mostly unfixable) on the PowerMac G5 AGP and Xserve G5 machines.

This had a bit of testing on a couple of PowerMac G5 AGP variants but none at all on Xserve G5 since the one I have is unfortunately dead.

Quoted 6 lines

If you want to help me test this, don't forget to disable therm_pm72, and instead load windfarm_pm72 or windfarm_rm31 depending on your machine (you can load or build-in the whole lot as well). As usual windfarm don't properly auto-load yet, I still need to fix that.

So please test ! Especially if you have an XServe G5

Quoted 10 lines

Benjamin, thanks a lot for doing this! These drivers were the last ones blocking the removal of the legacy binding model in i2c-core. Testers are very welcome. The earliest we can get these changes upstream, the better.

Christian, can you please test this series? I'm sure Benjamin can send the patches to you directly if needed.

Signature · 1 line
Jean Delvare

I may need a day or two to get to it, but I'll test it.

Thanks,
C.

Signature · 1 line
make bzImage, not war
#32 lore raw
In reply to Jean Delvare
Quoted 2 lines · Jean Delvare

Benjamin, thanks a lot for doing this! These drivers were the last ones blocking the removal of the legacy binding model in i2c-core.

There's a couple left :-) I haven't done therm_windtunnel.c (here too, I need testers when I'm done) and our sound drivers are still using the old API afaik, that's next on my list.

Quoted 6 lines

Testers
are very welcome. The earliest we can get these changes upstream, the better.

Christian, can you please test this series? I'm sure Benjamin can send the patches to you directly if needed.

The main problem is that I don't have a Xserve G5 anymore to test, that's one driver that largely rewritten and totally untested...

Cheers,
Ben.

A message that is not in the archive (sent off-list or not yet received): 20120419113723.03a24d46__2279.25503063506$1334829915$gmane$org@endymion.delvare

#34 lore raw
Quoted 2 lines · Jean Delvare

These drivers were the last ones blocking the removal of the legacy binding model in i2c-core.

There are also still some uses in snd-aoa.

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#35 lore raw

Hallo Andreas,

Quoted 6 lines · Andreas Schwab
Quoted 2 lines · Jean Delvare

These drivers were the last ones blocking the removal of the legacy binding model in i2c-core.

There are also still some uses in snd-aoa.

You're right, there are still 3 sound drivers which need to be converted (aoa/onyx, aoa/tas and ppc/keywest.) I believe Benjamin will take care of the latter when he is done with the thermal management drivers. Not sure who can work on and/or test the aoa sound drivers.

Signature · 1 line
Jean Delvare

A message that is not in the archive (sent off-list or not yet received): [email protected]

#37 lore raw
Quoted 6 lines · Andreas Schwab
Quoted 2 lines · Jean Delvare

These drivers were the last ones blocking the removal of the legacy binding model in i2c-core.

There are also still some uses in snd-aoa.

Never mind, I just found the commit in tiwai/sound.git.

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

A message that is not in the archive (sent off-list or not yet received): [email protected]

#39 lore raw
Quoted 10 lines · Andreas Schwab
Quoted 6 lines · Andreas Schwab
Quoted 2 lines · Jean Delvare

These drivers were the last ones blocking the removal of the legacy binding model in i2c-core.

There are also still some uses in snd-aoa.

Never mind, I just found the commit in tiwai/sound.git.

Confused.... this was some old one which has nothing to do with the legacy binding model conversion.

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

A message that is not in the archive (sent off-list or not yet received): 1334823416-9138-3-git-send-email-benh__10691.3206204355$1334826366$gmane$org@kernel.crashing.org

#41 lore raw

Re: [PATCH 02/15] powerpc/pmac: Convert therm_adt746x to new i2c probing

Tested on iBook G4 (PowerBook6,7).

Andreas.

Signature · 3 lines
Andreas Schwab, [email protected]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."