diff options
| -rw-r--r-- | drivers/hwmon/fschmd.c | 112 |
1 files changed, 57 insertions, 55 deletions
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index bd89d270a5ed..967170368933 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c | |||
| @@ -171,20 +171,37 @@ static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; | |||
| 171 | * Functions declarations | 171 | * Functions declarations |
| 172 | */ | 172 | */ |
| 173 | 173 | ||
| 174 | static int fschmd_attach_adapter(struct i2c_adapter *adapter); | 174 | static int fschmd_probe(struct i2c_client *client, |
| 175 | static int fschmd_detach_client(struct i2c_client *client); | 175 | const struct i2c_device_id *id); |
| 176 | static int fschmd_detect(struct i2c_client *client, int kind, | ||
| 177 | struct i2c_board_info *info); | ||
| 178 | static int fschmd_remove(struct i2c_client *client); | ||
| 176 | static struct fschmd_data *fschmd_update_device(struct device *dev); | 179 | static struct fschmd_data *fschmd_update_device(struct device *dev); |
| 177 | 180 | ||
| 178 | /* | 181 | /* |
| 179 | * Driver data (common to all clients) | 182 | * Driver data (common to all clients) |
| 180 | */ | 183 | */ |
| 181 | 184 | ||
| 185 | static const struct i2c_device_id fschmd_id[] = { | ||
| 186 | { "fscpos", fscpos }, | ||
| 187 | { "fscher", fscher }, | ||
| 188 | { "fscscy", fscscy }, | ||
| 189 | { "fschrc", fschrc }, | ||
| 190 | { "fschmd", fschmd }, | ||
| 191 | { } | ||
| 192 | }; | ||
| 193 | MODULE_DEVICE_TABLE(i2c, fschmd_id); | ||
| 194 | |||
| 182 | static struct i2c_driver fschmd_driver = { | 195 | static struct i2c_driver fschmd_driver = { |
| 196 | .class = I2C_CLASS_HWMON, | ||
| 183 | .driver = { | 197 | .driver = { |
| 184 | .name = FSCHMD_NAME, | 198 | .name = FSCHMD_NAME, |
| 185 | }, | 199 | }, |
| 186 | .attach_adapter = fschmd_attach_adapter, | 200 | .probe = fschmd_probe, |
| 187 | .detach_client = fschmd_detach_client, | 201 | .remove = fschmd_remove, |
| 202 | .id_table = fschmd_id, | ||
| 203 | .detect = fschmd_detect, | ||
| 204 | .address_data = &addr_data, | ||
| 188 | }; | 205 | }; |
| 189 | 206 | ||
| 190 | /* | 207 | /* |
| @@ -192,7 +209,6 @@ static struct i2c_driver fschmd_driver = { | |||
| 192 | */ | 209 | */ |
| 193 | 210 | ||
| 194 | struct fschmd_data { | 211 | struct fschmd_data { |
| 195 | struct i2c_client client; | ||
| 196 | struct device *hwmon_dev; | 212 | struct device *hwmon_dev; |
| 197 | struct mutex update_lock; | 213 | struct mutex update_lock; |
| 198 | int kind; | 214 | int kind; |
| @@ -269,7 +285,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute | |||
| 269 | v = SENSORS_LIMIT(v, -128, 127) + 128; | 285 | v = SENSORS_LIMIT(v, -128, 127) + 128; |
| 270 | 286 | ||
| 271 | mutex_lock(&data->update_lock); | 287 | mutex_lock(&data->update_lock); |
| 272 | i2c_smbus_write_byte_data(&data->client, | 288 | i2c_smbus_write_byte_data(to_i2c_client(dev), |
| 273 | FSCHMD_REG_TEMP_LIMIT[data->kind][index], v); | 289 | FSCHMD_REG_TEMP_LIMIT[data->kind][index], v); |
| 274 | data->temp_max[index] = v; | 290 | data->temp_max[index] = v; |
| 275 | mutex_unlock(&data->update_lock); | 291 | mutex_unlock(&data->update_lock); |
| @@ -346,14 +362,14 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute | |||
| 346 | 362 | ||
| 347 | mutex_lock(&data->update_lock); | 363 | mutex_lock(&data->update_lock); |
| 348 | 364 | ||
| 349 | reg = i2c_smbus_read_byte_data(&data->client, | 365 | reg = i2c_smbus_read_byte_data(to_i2c_client(dev), |
| 350 | FSCHMD_REG_FAN_RIPPLE[data->kind][index]); | 366 | FSCHMD_REG_FAN_RIPPLE[data->kind][index]); |
| 351 | 367 | ||
| 352 | /* bits 2..7 reserved => mask with 0x03 */ | 368 | /* bits 2..7 reserved => mask with 0x03 */ |
| 353 | reg &= ~0x03; | 369 | reg &= ~0x03; |
| 354 | reg |= v; | 370 | reg |= v; |
| 355 | 371 | ||
| 356 | i2c_smbus_write_byte_data(&data->client, | 372 | i2c_smbus_write_byte_data(to_i2c_client(dev), |
| 357 | FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg); | 373 | FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg); |
| 358 | 374 | ||
| 359 | data->fan_ripple[index] = reg; | 375 | data->fan_ripple[index] = reg; |
| @@ -416,7 +432,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, | |||
| 416 | 432 | ||
| 417 | mutex_lock(&data->update_lock); | 433 | mutex_lock(&data->update_lock); |
| 418 | 434 | ||
| 419 | i2c_smbus_write_byte_data(&data->client, | 435 | i2c_smbus_write_byte_data(to_i2c_client(dev), |
| 420 | FSCHMD_REG_FAN_MIN[data->kind][index], v); | 436 | FSCHMD_REG_FAN_MIN[data->kind][index], v); |
| 421 | data->fan_min[index] = v; | 437 | data->fan_min[index] = v; |
| 422 | 438 | ||
| @@ -448,14 +464,14 @@ static ssize_t store_alert_led(struct device *dev, | |||
| 448 | 464 | ||
| 449 | mutex_lock(&data->update_lock); | 465 | mutex_lock(&data->update_lock); |
| 450 | 466 | ||
| 451 | reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL); | 467 | reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL); |
| 452 | 468 | ||
| 453 | if (v) | 469 | if (v) |
| 454 | reg |= FSCHMD_CONTROL_ALERT_LED_MASK; | 470 | reg |= FSCHMD_CONTROL_ALERT_LED_MASK; |
| 455 | else | 471 | else |
| 456 | reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK; | 472 | reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK; |
| 457 | 473 | ||
| 458 | i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg); | 474 | i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg); |
| 459 | 475 | ||
| 460 | data->global_control = reg; | 476 | data->global_control = reg; |
| 461 | 477 | ||
| @@ -600,32 +616,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header) | |||
| 600 | } | 616 | } |
| 601 | } | 617 | } |
| 602 | 618 | ||
| 603 | static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) | 619 | static int fschmd_detect(struct i2c_client *client, int kind, |
| 620 | struct i2c_board_info *info) | ||
| 604 | { | 621 | { |
| 605 | struct i2c_client *client; | 622 | struct i2c_adapter *adapter = client->adapter; |
| 606 | struct fschmd_data *data; | ||
| 607 | u8 revision; | ||
| 608 | const char * const names[5] = { "Poseidon", "Hermes", "Scylla", | ||
| 609 | "Heracles", "Heimdall" }; | ||
| 610 | const char * const client_names[5] = { "fscpos", "fscher", "fscscy", | 623 | const char * const client_names[5] = { "fscpos", "fscher", "fscscy", |
| 611 | "fschrc", "fschmd" }; | 624 | "fschrc", "fschmd" }; |
| 612 | int i, err = 0; | ||
| 613 | 625 | ||
| 614 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 626 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
| 615 | return 0; | 627 | return -ENODEV; |
| 616 | |||
| 617 | /* OK. For now, we presume we have a valid client. We now create the | ||
| 618 | * client structure, even though we cannot fill it completely yet. | ||
| 619 | * But it allows us to access i2c_smbus_read_byte_data. */ | ||
| 620 | if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL))) | ||
| 621 | return -ENOMEM; | ||
| 622 | |||
| 623 | client = &data->client; | ||
| 624 | i2c_set_clientdata(client, data); | ||
| 625 | client->addr = address; | ||
| 626 | client->adapter = adapter; | ||
| 627 | client->driver = &fschmd_driver; | ||
| 628 | mutex_init(&data->update_lock); | ||
| 629 | 628 | ||
| 630 | /* Detect & Identify the chip */ | 629 | /* Detect & Identify the chip */ |
| 631 | if (kind <= 0) { | 630 | if (kind <= 0) { |
| @@ -650,9 +649,31 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 650 | else if (!strcmp(id, "HMD")) | 649 | else if (!strcmp(id, "HMD")) |
| 651 | kind = fschmd; | 650 | kind = fschmd; |
| 652 | else | 651 | else |
| 653 | goto exit_free; | 652 | return -ENODEV; |
| 654 | } | 653 | } |
| 655 | 654 | ||
| 655 | strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE); | ||
| 656 | |||
| 657 | return 0; | ||
| 658 | } | ||
| 659 | |||
| 660 | static int fschmd_probe(struct i2c_client *client, | ||
| 661 | const struct i2c_device_id *id) | ||
| 662 | { | ||
| 663 | struct fschmd_data *data; | ||
| 664 | u8 revision; | ||
| 665 | const char * const names[5] = { "Poseidon", "Hermes", "Scylla", | ||
| 666 | "Heracles", "Heimdall" }; | ||
| 667 | int i, err; | ||
| 668 | enum chips kind = id->driver_data; | ||
| 669 | |||
| 670 | data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL); | ||
| 671 | if (!data) | ||
| 672 | return -ENOMEM; | ||
| 673 | |||
| 674 | i2c_set_clientdata(client, data); | ||
| 675 | mutex_init(&data->update_lock); | ||
| 676 | |||
| 656 | if (kind == fscpos) { | 677 | if (kind == fscpos) { |
| 657 | /* The Poseidon has hardwired temp limits, fill these | 678 | /* The Poseidon has hardwired temp limits, fill these |
| 658 | in for the alarm resetting code */ | 679 | in for the alarm resetting code */ |
| @@ -674,11 +695,6 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 674 | 695 | ||
| 675 | /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ | 696 | /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ |
| 676 | data->kind = kind - 1; | 697 | data->kind = kind - 1; |
| 677 | strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE); | ||
| 678 | |||
| 679 | /* Tell the I2C layer a new client has arrived */ | ||
| 680 | if ((err = i2c_attach_client(client))) | ||
| 681 | goto exit_free; | ||
| 682 | 698 | ||
| 683 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { | 699 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { |
| 684 | err = device_create_file(&client->dev, | 700 | err = device_create_file(&client->dev, |
| @@ -726,25 +742,14 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 726 | return 0; | 742 | return 0; |
| 727 | 743 | ||
| 728 | exit_detach: | 744 | exit_detach: |
| 729 | fschmd_detach_client(client); /* will also free data for us */ | 745 | fschmd_remove(client); /* will also free data for us */ |
| 730 | return err; | ||
| 731 | |||
| 732 | exit_free: | ||
| 733 | kfree(data); | ||
| 734 | return err; | 746 | return err; |
| 735 | } | 747 | } |
| 736 | 748 | ||
| 737 | static int fschmd_attach_adapter(struct i2c_adapter *adapter) | 749 | static int fschmd_remove(struct i2c_client *client) |
| 738 | { | ||
| 739 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
| 740 | return 0; | ||
| 741 | return i2c_probe(adapter, &addr_data, fschmd_detect); | ||
| 742 | } | ||
| 743 | |||
| 744 | static int fschmd_detach_client(struct i2c_client *client) | ||
| 745 | { | 750 | { |
| 746 | struct fschmd_data *data = i2c_get_clientdata(client); | 751 | struct fschmd_data *data = i2c_get_clientdata(client); |
| 747 | int i, err; | 752 | int i; |
| 748 | 753 | ||
| 749 | /* Check if registered in case we're called from fschmd_detect | 754 | /* Check if registered in case we're called from fschmd_detect |
| 750 | to cleanup after an error */ | 755 | to cleanup after an error */ |
| @@ -760,9 +765,6 @@ static int fschmd_detach_client(struct i2c_client *client) | |||
| 760 | device_remove_file(&client->dev, | 765 | device_remove_file(&client->dev, |
| 761 | &fschmd_fan_attr[i].dev_attr); | 766 | &fschmd_fan_attr[i].dev_attr); |
| 762 | 767 | ||
| 763 | if ((err = i2c_detach_client(client))) | ||
| 764 | return err; | ||
| 765 | |||
| 766 | kfree(data); | 768 | kfree(data); |
| 767 | return 0; | 769 | return 0; |
| 768 | } | 770 | } |
