diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/gl518sm.c | 99 |
1 files changed, 47 insertions, 52 deletions
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 33e9e8a8d1ce..7820df45d77a 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c | |||
@@ -114,7 +114,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) | |||
114 | 114 | ||
115 | /* Each client has this additional data */ | 115 | /* Each client has this additional data */ |
116 | struct gl518_data { | 116 | struct gl518_data { |
117 | struct i2c_client client; | ||
118 | struct device *hwmon_dev; | 117 | struct device *hwmon_dev; |
119 | enum chips type; | 118 | enum chips type; |
120 | 119 | ||
@@ -138,21 +137,33 @@ struct gl518_data { | |||
138 | u8 beep_enable; /* Boolean */ | 137 | u8 beep_enable; /* Boolean */ |
139 | }; | 138 | }; |
140 | 139 | ||
141 | static int gl518_attach_adapter(struct i2c_adapter *adapter); | 140 | static int gl518_probe(struct i2c_client *client, |
142 | static int gl518_detect(struct i2c_adapter *adapter, int address, int kind); | 141 | const struct i2c_device_id *id); |
142 | static int gl518_detect(struct i2c_client *client, int kind, | ||
143 | struct i2c_board_info *info); | ||
143 | static void gl518_init_client(struct i2c_client *client); | 144 | static void gl518_init_client(struct i2c_client *client); |
144 | static int gl518_detach_client(struct i2c_client *client); | 145 | static int gl518_remove(struct i2c_client *client); |
145 | static int gl518_read_value(struct i2c_client *client, u8 reg); | 146 | static int gl518_read_value(struct i2c_client *client, u8 reg); |
146 | static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); | 147 | static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); |
147 | static struct gl518_data *gl518_update_device(struct device *dev); | 148 | static struct gl518_data *gl518_update_device(struct device *dev); |
148 | 149 | ||
150 | static const struct i2c_device_id gl518_id[] = { | ||
151 | { "gl518sm", 0 }, | ||
152 | { } | ||
153 | }; | ||
154 | MODULE_DEVICE_TABLE(i2c, gl518_id); | ||
155 | |||
149 | /* This is the driver that will be inserted */ | 156 | /* This is the driver that will be inserted */ |
150 | static struct i2c_driver gl518_driver = { | 157 | static struct i2c_driver gl518_driver = { |
158 | .class = I2C_CLASS_HWMON, | ||
151 | .driver = { | 159 | .driver = { |
152 | .name = "gl518sm", | 160 | .name = "gl518sm", |
153 | }, | 161 | }, |
154 | .attach_adapter = gl518_attach_adapter, | 162 | .probe = gl518_probe, |
155 | .detach_client = gl518_detach_client, | 163 | .remove = gl518_remove, |
164 | .id_table = gl518_id, | ||
165 | .detect = gl518_detect, | ||
166 | .address_data = &addr_data, | ||
156 | }; | 167 | }; |
157 | 168 | ||
158 | /* | 169 | /* |
@@ -472,46 +483,23 @@ static const struct attribute_group gl518_group_r80 = { | |||
472 | * Real code | 483 | * Real code |
473 | */ | 484 | */ |
474 | 485 | ||
475 | static int gl518_attach_adapter(struct i2c_adapter *adapter) | 486 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
476 | { | 487 | static int gl518_detect(struct i2c_client *client, int kind, |
477 | if (!(adapter->class & I2C_CLASS_HWMON)) | 488 | struct i2c_board_info *info) |
478 | return 0; | ||
479 | return i2c_probe(adapter, &addr_data, gl518_detect); | ||
480 | } | ||
481 | |||
482 | static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) | ||
483 | { | 489 | { |
490 | struct i2c_adapter *adapter = client->adapter; | ||
484 | int i; | 491 | int i; |
485 | struct i2c_client *client; | ||
486 | struct gl518_data *data; | ||
487 | int err = 0; | ||
488 | 492 | ||
489 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | | 493 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | |
490 | I2C_FUNC_SMBUS_WORD_DATA)) | 494 | I2C_FUNC_SMBUS_WORD_DATA)) |
491 | goto exit; | 495 | return -ENODEV; |
492 | |||
493 | /* OK. For now, we presume we have a valid client. We now create the | ||
494 | client structure, even though we cannot fill it completely yet. | ||
495 | But it allows us to access gl518_{read,write}_value. */ | ||
496 | |||
497 | if (!(data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL))) { | ||
498 | err = -ENOMEM; | ||
499 | goto exit; | ||
500 | } | ||
501 | |||
502 | client = &data->client; | ||
503 | i2c_set_clientdata(client, data); | ||
504 | |||
505 | client->addr = address; | ||
506 | client->adapter = adapter; | ||
507 | client->driver = &gl518_driver; | ||
508 | 496 | ||
509 | /* Now, we do the remaining detection. */ | 497 | /* Now, we do the remaining detection. */ |
510 | 498 | ||
511 | if (kind < 0) { | 499 | if (kind < 0) { |
512 | if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80) | 500 | if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80) |
513 | || (gl518_read_value(client, GL518_REG_CONF) & 0x80)) | 501 | || (gl518_read_value(client, GL518_REG_CONF) & 0x80)) |
514 | goto exit_free; | 502 | return -ENODEV; |
515 | } | 503 | } |
516 | 504 | ||
517 | /* Determine the chip type. */ | 505 | /* Determine the chip type. */ |
@@ -526,19 +514,32 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) | |||
526 | dev_info(&adapter->dev, | 514 | dev_info(&adapter->dev, |
527 | "Ignoring 'force' parameter for unknown " | 515 | "Ignoring 'force' parameter for unknown " |
528 | "chip at adapter %d, address 0x%02x\n", | 516 | "chip at adapter %d, address 0x%02x\n", |
529 | i2c_adapter_id(adapter), address); | 517 | i2c_adapter_id(adapter), client->addr); |
530 | goto exit_free; | 518 | return -ENODEV; |
531 | } | 519 | } |
532 | } | 520 | } |
533 | 521 | ||
534 | /* Fill in the remaining client fields */ | 522 | strlcpy(info->type, "gl518sm", I2C_NAME_SIZE); |
535 | strlcpy(client->name, "gl518sm", I2C_NAME_SIZE); | ||
536 | data->type = kind; | ||
537 | mutex_init(&data->update_lock); | ||
538 | 523 | ||
539 | /* Tell the I2C layer a new client has arrived */ | 524 | return 0; |
540 | if ((err = i2c_attach_client(client))) | 525 | } |
541 | goto exit_free; | 526 | |
527 | static int gl518_probe(struct i2c_client *client, | ||
528 | const struct i2c_device_id *id) | ||
529 | { | ||
530 | struct gl518_data *data; | ||
531 | int err, revision; | ||
532 | |||
533 | data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL); | ||
534 | if (!data) { | ||
535 | err = -ENOMEM; | ||
536 | goto exit; | ||
537 | } | ||
538 | |||
539 | i2c_set_clientdata(client, data); | ||
540 | revision = gl518_read_value(client, GL518_REG_REVISION); | ||
541 | data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00; | ||
542 | mutex_init(&data->update_lock); | ||
542 | 543 | ||
543 | /* Initialize the GL518SM chip */ | 544 | /* Initialize the GL518SM chip */ |
544 | data->alarm_mask = 0xff; | 545 | data->alarm_mask = 0xff; |
@@ -546,7 +547,7 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) | |||
546 | 547 | ||
547 | /* Register sysfs hooks */ | 548 | /* Register sysfs hooks */ |
548 | if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group))) | 549 | if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group))) |
549 | goto exit_detach; | 550 | goto exit_free; |
550 | if (data->type == gl518sm_r80) | 551 | if (data->type == gl518sm_r80) |
551 | if ((err = sysfs_create_group(&client->dev.kobj, | 552 | if ((err = sysfs_create_group(&client->dev.kobj, |
552 | &gl518_group_r80))) | 553 | &gl518_group_r80))) |
@@ -564,8 +565,6 @@ exit_remove_files: | |||
564 | sysfs_remove_group(&client->dev.kobj, &gl518_group); | 565 | sysfs_remove_group(&client->dev.kobj, &gl518_group); |
565 | if (data->type == gl518sm_r80) | 566 | if (data->type == gl518sm_r80) |
566 | sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); | 567 | sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); |
567 | exit_detach: | ||
568 | i2c_detach_client(client); | ||
569 | exit_free: | 568 | exit_free: |
570 | kfree(data); | 569 | kfree(data); |
571 | exit: | 570 | exit: |
@@ -591,19 +590,15 @@ static void gl518_init_client(struct i2c_client *client) | |||
591 | gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); | 590 | gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); |
592 | } | 591 | } |
593 | 592 | ||
594 | static int gl518_detach_client(struct i2c_client *client) | 593 | static int gl518_remove(struct i2c_client *client) |
595 | { | 594 | { |
596 | struct gl518_data *data = i2c_get_clientdata(client); | 595 | struct gl518_data *data = i2c_get_clientdata(client); |
597 | int err; | ||
598 | 596 | ||
599 | hwmon_device_unregister(data->hwmon_dev); | 597 | hwmon_device_unregister(data->hwmon_dev); |
600 | sysfs_remove_group(&client->dev.kobj, &gl518_group); | 598 | sysfs_remove_group(&client->dev.kobj, &gl518_group); |
601 | if (data->type == gl518sm_r80) | 599 | if (data->type == gl518sm_r80) |
602 | sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); | 600 | sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); |
603 | 601 | ||
604 | if ((err = i2c_detach_client(client))) | ||
605 | return err; | ||
606 | |||
607 | kfree(data); | 602 | kfree(data); |
608 | return 0; | 603 | return 0; |
609 | } | 604 | } |