aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOctavian Purdila <octavian.purdila@intel.com>2016-07-08 12:13:11 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-07-08 15:52:35 -0400
commit7f24467f3b357ab6abc146c47fcedd7d57a189b6 (patch)
treef10e4517ba422e4ed292c13609fc599fb03bb722
parent525e6fabeae286848592363bda13bc34b59bb5ac (diff)
spi / ACPI: add support for ACPI reconfigure notifications
This patch adds supports for SPI device enumeration and removal via ACPI reconfiguration notifications that are send as a result of an ACPI table load or unload operation. The code is very similar with the device tree reconfiguration code with only small differences in the way we test and set the enumerated state of the device: * the equivalent of device tree's OF_POPULATED flag is the flags.visited field in the ACPI device and the following wrappers are used to manipulate it: acpi_device_enumerated(), acpi_device_set_enumerated() and acpi_device_clear_enumerated() * the device tree code checks of status of the OF_POPULATED flag to avoid trying to create duplicate Linux devices in two places: once when the controller is probed, and once when the reconfigure event is received; in the ACPI code the check is performed only once when the ACPI namespace is searched because this code path is invoked in both of the two mentioned cases The rest of the enumeration handling is similar with device tree: when the Linux device is unregistered the ACPI device is marked as not enumerated; also, when a device remove notification is received we check that the device is in the enumerated state before continuing with the removal of the Linux device. Signed-off-by: Octavian Purdila <octavian.purdila@intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Mark Brown <broonie@kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/spi/spi.c100
1 files changed, 93 insertions, 7 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 77e6e45951f4..7589c8af4368 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -622,6 +622,8 @@ void spi_unregister_device(struct spi_device *spi)
622 622
623 if (spi->dev.of_node) 623 if (spi->dev.of_node)
624 of_node_clear_flag(spi->dev.of_node, OF_POPULATED); 624 of_node_clear_flag(spi->dev.of_node, OF_POPULATED);
625 if (ACPI_COMPANION(&spi->dev))
626 acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev));
625 device_unregister(&spi->dev); 627 device_unregister(&spi->dev);
626} 628}
627EXPORT_SYMBOL_GPL(spi_unregister_device); 629EXPORT_SYMBOL_GPL(spi_unregister_device);
@@ -1646,18 +1648,15 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
1646 return 1; 1648 return 1;
1647} 1649}
1648 1650
1649static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, 1651static acpi_status acpi_register_spi_device(struct spi_master *master,
1650 void *data, void **return_value) 1652 struct acpi_device *adev)
1651{ 1653{
1652 struct spi_master *master = data;
1653 struct list_head resource_list; 1654 struct list_head resource_list;
1654 struct acpi_device *adev;
1655 struct spi_device *spi; 1655 struct spi_device *spi;
1656 int ret; 1656 int ret;
1657 1657
1658 if (acpi_bus_get_device(handle, &adev)) 1658 if (acpi_bus_get_status(adev) || !adev->status.present ||
1659 return AE_OK; 1659 acpi_device_enumerated(adev))
1660 if (acpi_bus_get_status(adev) || !adev->status.present)
1661 return AE_OK; 1660 return AE_OK;
1662 1661
1663 spi = spi_alloc_device(master); 1662 spi = spi_alloc_device(master);
@@ -1683,6 +1682,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
1683 if (spi->irq < 0) 1682 if (spi->irq < 0)
1684 spi->irq = acpi_dev_gpio_irq_get(adev, 0); 1683 spi->irq = acpi_dev_gpio_irq_get(adev, 0);
1685 1684
1685 acpi_device_set_enumerated(adev);
1686
1686 adev->power.flags.ignore_parent = true; 1687 adev->power.flags.ignore_parent = true;
1687 strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); 1688 strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias));
1688 if (spi_add_device(spi)) { 1689 if (spi_add_device(spi)) {
@@ -1695,6 +1696,18 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
1695 return AE_OK; 1696 return AE_OK;
1696} 1697}
1697 1698
1699static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
1700 void *data, void **return_value)
1701{
1702 struct spi_master *master = data;
1703 struct acpi_device *adev;
1704
1705 if (acpi_bus_get_device(handle, &adev))
1706 return AE_OK;
1707
1708 return acpi_register_spi_device(master, adev);
1709}
1710
1698static void acpi_register_spi_devices(struct spi_master *master) 1711static void acpi_register_spi_devices(struct spi_master *master)
1699{ 1712{
1700 acpi_status status; 1713 acpi_status status;
@@ -3107,6 +3120,77 @@ static struct notifier_block spi_of_notifier = {
3107extern struct notifier_block spi_of_notifier; 3120extern struct notifier_block spi_of_notifier;
3108#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ 3121#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
3109 3122
3123#if IS_ENABLED(CONFIG_ACPI)
3124static int spi_acpi_master_match(struct device *dev, const void *data)
3125{
3126 return ACPI_COMPANION(dev->parent) == data;
3127}
3128
3129static int spi_acpi_device_match(struct device *dev, void *data)
3130{
3131 return ACPI_COMPANION(dev) == data;
3132}
3133
3134static struct spi_master *acpi_spi_find_master_by_adev(struct acpi_device *adev)
3135{
3136 struct device *dev;
3137
3138 dev = class_find_device(&spi_master_class, NULL, adev,
3139 spi_acpi_master_match);
3140 if (!dev)
3141 return NULL;
3142
3143 return container_of(dev, struct spi_master, dev);
3144}
3145
3146static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev)
3147{
3148 struct device *dev;
3149
3150 dev = bus_find_device(&spi_bus_type, NULL, adev, spi_acpi_device_match);
3151
3152 return dev ? to_spi_device(dev) : NULL;
3153}
3154
3155static int acpi_spi_notify(struct notifier_block *nb, unsigned long value,
3156 void *arg)
3157{
3158 struct acpi_device *adev = arg;
3159 struct spi_master *master;
3160 struct spi_device *spi;
3161
3162 switch (value) {
3163 case ACPI_RECONFIG_DEVICE_ADD:
3164 master = acpi_spi_find_master_by_adev(adev->parent);
3165 if (!master)
3166 break;
3167
3168 acpi_register_spi_device(master, adev);
3169 put_device(&master->dev);
3170 break;
3171 case ACPI_RECONFIG_DEVICE_REMOVE:
3172 if (!acpi_device_enumerated(adev))
3173 break;
3174
3175 spi = acpi_spi_find_device_by_adev(adev);
3176 if (!spi)
3177 break;
3178
3179 spi_unregister_device(spi);
3180 put_device(&spi->dev);
3181 break;
3182 }
3183
3184 return NOTIFY_OK;
3185}
3186
3187static struct notifier_block spi_acpi_notifier = {
3188 .notifier_call = acpi_spi_notify,
3189};
3190#else
3191extern struct notifier_block spi_acpi_notifier;
3192#endif
3193
3110static int __init spi_init(void) 3194static int __init spi_init(void)
3111{ 3195{
3112 int status; 3196 int status;
@@ -3127,6 +3211,8 @@ static int __init spi_init(void)
3127 3211
3128 if (IS_ENABLED(CONFIG_OF_DYNAMIC)) 3212 if (IS_ENABLED(CONFIG_OF_DYNAMIC))
3129 WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); 3213 WARN_ON(of_reconfig_notifier_register(&spi_of_notifier));
3214 if (IS_ENABLED(CONFIG_ACPI))
3215 WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier));
3130 3216
3131 return 0; 3217 return 0;
3132 3218