diff options
author | Jean Delvare <khali@linux-fr.org> | 2008-10-17 11:51:16 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-10-17 11:51:16 -0400 |
commit | 0c6e97317102a8f480bdfb418f19fe989ad1c047 (patch) | |
tree | e4174ba35c27d96bcc11562002f80862967cf8c3 /drivers/hwmon | |
parent | 6e1b5029dc0e4cfa765309312ebdc88711e37a20 (diff) |
hwmon: (lm78) Convert to a new-style i2c driver
The new-style lm78 driver implements the optional detect() callback
to cover the use cases of the legacy driver.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/lm78.c | 194 |
1 files changed, 89 insertions, 105 deletions
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 177eaddde321..b5e3b2851698 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c | |||
@@ -115,7 +115,7 @@ static inline int TEMP_FROM_REG(s8 val) | |||
115 | #define DIV_FROM_REG(val) (1 << (val)) | 115 | #define DIV_FROM_REG(val) (1 << (val)) |
116 | 116 | ||
117 | struct lm78_data { | 117 | struct lm78_data { |
118 | struct i2c_client client; | 118 | struct i2c_client *client; |
119 | struct device *hwmon_dev; | 119 | struct device *hwmon_dev; |
120 | struct mutex lock; | 120 | struct mutex lock; |
121 | enum chips type; | 121 | enum chips type; |
@@ -142,9 +142,11 @@ struct lm78_data { | |||
142 | }; | 142 | }; |
143 | 143 | ||
144 | 144 | ||
145 | static int lm78_attach_adapter(struct i2c_adapter *adapter); | 145 | static int lm78_i2c_detect(struct i2c_client *client, int kind, |
146 | static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); | 146 | struct i2c_board_info *info); |
147 | static int lm78_detach_client(struct i2c_client *client); | 147 | static int lm78_i2c_probe(struct i2c_client *client, |
148 | const struct i2c_device_id *id); | ||
149 | static int lm78_i2c_remove(struct i2c_client *client); | ||
148 | 150 | ||
149 | static int __devinit lm78_isa_probe(struct platform_device *pdev); | 151 | static int __devinit lm78_isa_probe(struct platform_device *pdev); |
150 | static int __devexit lm78_isa_remove(struct platform_device *pdev); | 152 | static int __devexit lm78_isa_remove(struct platform_device *pdev); |
@@ -155,12 +157,23 @@ static struct lm78_data *lm78_update_device(struct device *dev); | |||
155 | static void lm78_init_device(struct lm78_data *data); | 157 | static void lm78_init_device(struct lm78_data *data); |
156 | 158 | ||
157 | 159 | ||
160 | static const struct i2c_device_id lm78_i2c_id[] = { | ||
161 | { "lm78", lm78 }, | ||
162 | { "lm79", lm79 }, | ||
163 | { } | ||
164 | }; | ||
165 | MODULE_DEVICE_TABLE(i2c, lm78_i2c_id); | ||
166 | |||
158 | static struct i2c_driver lm78_driver = { | 167 | static struct i2c_driver lm78_driver = { |
168 | .class = I2C_CLASS_HWMON, | ||
159 | .driver = { | 169 | .driver = { |
160 | .name = "lm78", | 170 | .name = "lm78", |
161 | }, | 171 | }, |
162 | .attach_adapter = lm78_attach_adapter, | 172 | .probe = lm78_i2c_probe, |
163 | .detach_client = lm78_detach_client, | 173 | .remove = lm78_i2c_remove, |
174 | .id_table = lm78_i2c_id, | ||
175 | .detect = lm78_i2c_detect, | ||
176 | .address_data = &addr_data, | ||
164 | }; | 177 | }; |
165 | 178 | ||
166 | static struct platform_driver lm78_isa_driver = { | 179 | static struct platform_driver lm78_isa_driver = { |
@@ -445,29 +458,6 @@ static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); | |||
445 | static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); | 458 | static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); |
446 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); | 459 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); |
447 | 460 | ||
448 | /* This function is called when: | ||
449 | * lm78_driver is inserted (when this module is loaded), for each | ||
450 | available adapter | ||
451 | * when a new adapter is inserted (and lm78_driver is still present) | ||
452 | We block updates of the ISA device to minimize the risk of concurrent | ||
453 | access to the same LM78 chip through different interfaces. */ | ||
454 | static int lm78_attach_adapter(struct i2c_adapter *adapter) | ||
455 | { | ||
456 | struct lm78_data *data; | ||
457 | int err; | ||
458 | |||
459 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
460 | return 0; | ||
461 | |||
462 | data = pdev ? platform_get_drvdata(pdev) : NULL; | ||
463 | if (data) | ||
464 | mutex_lock(&data->update_lock); | ||
465 | err = i2c_probe(adapter, &addr_data, lm78_detect); | ||
466 | if (data) | ||
467 | mutex_unlock(&data->update_lock); | ||
468 | return err; | ||
469 | } | ||
470 | |||
471 | static struct attribute *lm78_attributes[] = { | 461 | static struct attribute *lm78_attributes[] = { |
472 | &sensor_dev_attr_in0_input.dev_attr.attr, | 462 | &sensor_dev_attr_in0_input.dev_attr.attr, |
473 | &sensor_dev_attr_in0_min.dev_attr.attr, | 463 | &sensor_dev_attr_in0_min.dev_attr.attr, |
@@ -537,13 +527,11 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | |||
537 | /* Returns 1 if the I2C chip appears to be an alias of the ISA chip */ | 527 | /* Returns 1 if the I2C chip appears to be an alias of the ISA chip */ |
538 | static int lm78_alias_detect(struct i2c_client *client, u8 chipid) | 528 | static int lm78_alias_detect(struct i2c_client *client, u8 chipid) |
539 | { | 529 | { |
540 | struct lm78_data *i2c, *isa; | 530 | struct lm78_data *isa; |
541 | int i; | 531 | int i; |
542 | 532 | ||
543 | if (!pdev) /* No ISA chip */ | 533 | if (!pdev) /* No ISA chip */ |
544 | return 0; | 534 | return 0; |
545 | |||
546 | i2c = i2c_get_clientdata(client); | ||
547 | isa = platform_get_drvdata(pdev); | 535 | isa = platform_get_drvdata(pdev); |
548 | 536 | ||
549 | if (lm78_read_value(isa, LM78_REG_I2C_ADDR) != client->addr) | 537 | if (lm78_read_value(isa, LM78_REG_I2C_ADDR) != client->addr) |
@@ -554,70 +542,55 @@ static int lm78_alias_detect(struct i2c_client *client, u8 chipid) | |||
554 | /* We compare all the limit registers, the config register and the | 542 | /* We compare all the limit registers, the config register and the |
555 | * interrupt mask registers */ | 543 | * interrupt mask registers */ |
556 | for (i = 0x2b; i <= 0x3d; i++) { | 544 | for (i = 0x2b; i <= 0x3d; i++) { |
557 | if (lm78_read_value(isa, i) != lm78_read_value(i2c, i)) | 545 | if (lm78_read_value(isa, i) != |
546 | i2c_smbus_read_byte_data(client, i)) | ||
558 | return 0; | 547 | return 0; |
559 | } | 548 | } |
560 | if (lm78_read_value(isa, LM78_REG_CONFIG) != | 549 | if (lm78_read_value(isa, LM78_REG_CONFIG) != |
561 | lm78_read_value(i2c, LM78_REG_CONFIG)) | 550 | i2c_smbus_read_byte_data(client, LM78_REG_CONFIG)) |
562 | return 0; | 551 | return 0; |
563 | for (i = 0x43; i <= 0x46; i++) { | 552 | for (i = 0x43; i <= 0x46; i++) { |
564 | if (lm78_read_value(isa, i) != lm78_read_value(i2c, i)) | 553 | if (lm78_read_value(isa, i) != |
554 | i2c_smbus_read_byte_data(client, i)) | ||
565 | return 0; | 555 | return 0; |
566 | } | 556 | } |
567 | 557 | ||
568 | return 1; | 558 | return 1; |
569 | } | 559 | } |
570 | 560 | ||
571 | /* This function is called by i2c_probe */ | 561 | static int lm78_i2c_detect(struct i2c_client *client, int kind, |
572 | static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) | 562 | struct i2c_board_info *info) |
573 | { | 563 | { |
574 | int i, err; | 564 | int i; |
575 | struct i2c_client *new_client; | 565 | struct lm78_data *isa = pdev ? platform_get_drvdata(pdev) : NULL; |
576 | struct lm78_data *data; | 566 | const char *client_name; |
577 | const char *client_name = ""; | 567 | struct i2c_adapter *adapter = client->adapter; |
578 | 568 | int address = client->addr; | |
579 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
580 | err = -ENODEV; | ||
581 | goto ERROR1; | ||
582 | } | ||
583 | |||
584 | /* OK. For now, we presume we have a valid client. We now create the | ||
585 | client structure, even though we cannot fill it completely yet. | ||
586 | But it allows us to access lm78_{read,write}_value. */ | ||
587 | 569 | ||
588 | if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) { | 570 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
589 | err = -ENOMEM; | 571 | return -ENODEV; |
590 | goto ERROR1; | ||
591 | } | ||
592 | 572 | ||
593 | new_client = &data->client; | 573 | /* We block updates of the ISA device to minimize the risk of |
594 | i2c_set_clientdata(new_client, data); | 574 | concurrent access to the same LM78 chip through different |
595 | new_client->addr = address; | 575 | interfaces. */ |
596 | new_client->adapter = adapter; | 576 | if (isa) |
597 | new_client->driver = &lm78_driver; | 577 | mutex_lock(&isa->update_lock); |
598 | 578 | ||
599 | /* Now, we do the remaining detection. */ | ||
600 | if (kind < 0) { | 579 | if (kind < 0) { |
601 | if (lm78_read_value(data, LM78_REG_CONFIG) & 0x80) { | 580 | if ((i2c_smbus_read_byte_data(client, LM78_REG_CONFIG) & 0x80) |
602 | err = -ENODEV; | 581 | || i2c_smbus_read_byte_data(client, LM78_REG_I2C_ADDR) |
603 | goto ERROR2; | 582 | != address) |
604 | } | 583 | goto err_nodev; |
605 | if (lm78_read_value(data, LM78_REG_I2C_ADDR) != | 584 | |
606 | address) { | ||
607 | err = -ENODEV; | ||
608 | goto ERROR2; | ||
609 | } | ||
610 | /* Explicitly prevent the misdetection of Winbond chips */ | 585 | /* Explicitly prevent the misdetection of Winbond chips */ |
611 | i = lm78_read_value(data, 0x4f); | 586 | i = i2c_smbus_read_byte_data(client, 0x4f); |
612 | if (i == 0xa3 || i == 0x5c) { | 587 | if (i == 0xa3 || i == 0x5c) |
613 | err = -ENODEV; | 588 | goto err_nodev; |
614 | goto ERROR2; | ||
615 | } | ||
616 | } | 589 | } |
617 | 590 | ||
618 | /* Determine the chip type. */ | 591 | /* Determine the chip type. */ |
619 | if (kind <= 0) { | 592 | if (kind <= 0) { |
620 | i = lm78_read_value(data, LM78_REG_CHIPID); | 593 | i = i2c_smbus_read_byte_data(client, LM78_REG_CHIPID); |
621 | if (i == 0x00 || i == 0x20 /* LM78 */ | 594 | if (i == 0x00 || i == 0x20 /* LM78 */ |
622 | || i == 0x40) /* LM78-J */ | 595 | || i == 0x40) /* LM78-J */ |
623 | kind = lm78; | 596 | kind = lm78; |
@@ -629,40 +602,59 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) | |||
629 | "parameter for unknown chip at " | 602 | "parameter for unknown chip at " |
630 | "adapter %d, address 0x%02x\n", | 603 | "adapter %d, address 0x%02x\n", |
631 | i2c_adapter_id(adapter), address); | 604 | i2c_adapter_id(adapter), address); |
632 | err = -ENODEV; | 605 | goto err_nodev; |
633 | goto ERROR2; | ||
634 | } | 606 | } |
635 | 607 | ||
636 | if (lm78_alias_detect(new_client, i)) { | 608 | if (lm78_alias_detect(client, i)) { |
637 | dev_dbg(&adapter->dev, "Device at 0x%02x appears to " | 609 | dev_dbg(&adapter->dev, "Device at 0x%02x appears to " |
638 | "be the same as ISA device\n", address); | 610 | "be the same as ISA device\n", address); |
639 | err = -ENODEV; | 611 | goto err_nodev; |
640 | goto ERROR2; | ||
641 | } | 612 | } |
642 | } | 613 | } |
643 | 614 | ||
644 | if (kind == lm78) { | 615 | if (isa) |
645 | client_name = "lm78"; | 616 | mutex_unlock(&isa->update_lock); |
646 | } else if (kind == lm79) { | 617 | |
618 | switch (kind) { | ||
619 | case lm79: | ||
647 | client_name = "lm79"; | 620 | client_name = "lm79"; |
621 | break; | ||
622 | default: | ||
623 | client_name = "lm78"; | ||
648 | } | 624 | } |
625 | strlcpy(info->type, client_name, I2C_NAME_SIZE); | ||
649 | 626 | ||
650 | /* Fill in the remaining client fields and put into the global list */ | 627 | return 0; |
651 | strlcpy(new_client->name, client_name, I2C_NAME_SIZE); | ||
652 | data->type = kind; | ||
653 | 628 | ||
654 | /* Tell the I2C layer a new client has arrived */ | 629 | err_nodev: |
655 | if ((err = i2c_attach_client(new_client))) | 630 | if (isa) |
656 | goto ERROR2; | 631 | mutex_unlock(&isa->update_lock); |
632 | return -ENODEV; | ||
633 | } | ||
634 | |||
635 | static int lm78_i2c_probe(struct i2c_client *client, | ||
636 | const struct i2c_device_id *id) | ||
637 | { | ||
638 | struct lm78_data *data; | ||
639 | int err; | ||
640 | |||
641 | data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL); | ||
642 | if (!data) | ||
643 | return -ENOMEM; | ||
644 | |||
645 | i2c_set_clientdata(client, data); | ||
646 | data->client = client; | ||
647 | data->type = id->driver_data; | ||
657 | 648 | ||
658 | /* Initialize the LM78 chip */ | 649 | /* Initialize the LM78 chip */ |
659 | lm78_init_device(data); | 650 | lm78_init_device(data); |
660 | 651 | ||
661 | /* Register sysfs hooks */ | 652 | /* Register sysfs hooks */ |
662 | if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group))) | 653 | err = sysfs_create_group(&client->dev.kobj, &lm78_group); |
654 | if (err) | ||
663 | goto ERROR3; | 655 | goto ERROR3; |
664 | 656 | ||
665 | data->hwmon_dev = hwmon_device_register(&new_client->dev); | 657 | data->hwmon_dev = hwmon_device_register(&client->dev); |
666 | if (IS_ERR(data->hwmon_dev)) { | 658 | if (IS_ERR(data->hwmon_dev)) { |
667 | err = PTR_ERR(data->hwmon_dev); | 659 | err = PTR_ERR(data->hwmon_dev); |
668 | goto ERROR4; | 660 | goto ERROR4; |
@@ -671,26 +663,18 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) | |||
671 | return 0; | 663 | return 0; |
672 | 664 | ||
673 | ERROR4: | 665 | ERROR4: |
674 | sysfs_remove_group(&new_client->dev.kobj, &lm78_group); | 666 | sysfs_remove_group(&client->dev.kobj, &lm78_group); |
675 | ERROR3: | 667 | ERROR3: |
676 | i2c_detach_client(new_client); | ||
677 | ERROR2: | ||
678 | kfree(data); | 668 | kfree(data); |
679 | ERROR1: | ||
680 | return err; | 669 | return err; |
681 | } | 670 | } |
682 | 671 | ||
683 | static int lm78_detach_client(struct i2c_client *client) | 672 | static int lm78_i2c_remove(struct i2c_client *client) |
684 | { | 673 | { |
685 | struct lm78_data *data = i2c_get_clientdata(client); | 674 | struct lm78_data *data = i2c_get_clientdata(client); |
686 | int err; | ||
687 | 675 | ||
688 | hwmon_device_unregister(data->hwmon_dev); | 676 | hwmon_device_unregister(data->hwmon_dev); |
689 | sysfs_remove_group(&client->dev.kobj, &lm78_group); | 677 | sysfs_remove_group(&client->dev.kobj, &lm78_group); |
690 | |||
691 | if ((err = i2c_detach_client(client))) | ||
692 | return err; | ||
693 | |||
694 | kfree(data); | 678 | kfree(data); |
695 | 679 | ||
696 | return 0; | 680 | return 0; |
@@ -774,9 +758,9 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev) | |||
774 | would slow down the LM78 access and should not be necessary. */ | 758 | would slow down the LM78 access and should not be necessary. */ |
775 | static int lm78_read_value(struct lm78_data *data, u8 reg) | 759 | static int lm78_read_value(struct lm78_data *data, u8 reg) |
776 | { | 760 | { |
777 | struct i2c_client *client = &data->client; | 761 | struct i2c_client *client = data->client; |
778 | 762 | ||
779 | if (!client->driver) { /* ISA device */ | 763 | if (!client) { /* ISA device */ |
780 | int res; | 764 | int res; |
781 | mutex_lock(&data->lock); | 765 | mutex_lock(&data->lock); |
782 | outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); | 766 | outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); |
@@ -796,9 +780,9 @@ static int lm78_read_value(struct lm78_data *data, u8 reg) | |||
796 | nowhere else be necessary! */ | 780 | nowhere else be necessary! */ |
797 | static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) | 781 | static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) |
798 | { | 782 | { |
799 | struct i2c_client *client = &data->client; | 783 | struct i2c_client *client = data->client; |
800 | 784 | ||
801 | if (!client->driver) { /* ISA device */ | 785 | if (!client) { /* ISA device */ |
802 | mutex_lock(&data->lock); | 786 | mutex_lock(&data->lock); |
803 | outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); | 787 | outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); |
804 | outb_p(value, data->isa_addr + LM78_DATA_REG_OFFSET); | 788 | outb_p(value, data->isa_addr + LM78_DATA_REG_OFFSET); |