Skip to content

Commit

Permalink
powerpc/pmac: Convert windfarm_smu_sat to new i2c probing
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Benjamin Herrenschmidt committed Apr 30, 2012
1 parent 22b6d2e commit e326b30
Showing 1 changed file with 47 additions and 79 deletions.
126 changes: 47 additions & 79 deletions drivers/macintosh/windfarm_smu_sat.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include "windfarm.h"

#define VERSION "0.2"
#define VERSION "1.0"

#define DEBUG

Expand All @@ -34,23 +34,25 @@
#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;
};

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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}

Expand All @@ -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,
Expand All @@ -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 <paulus@samba.org>");
MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
Expand Down

0 comments on commit e326b30

Please sign in to comment.