diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-11-30 06:38:51 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-11-30 06:38:51 -0500 |
commit | d9ba1025a46d368bc00a2981cb2b2a918e9209b7 (patch) | |
tree | c0451a56f972b01e16c776b572a23b4371ce5c5d | |
parent | ad063fbbdda6247c4653b708bf011986e8ab7ec8 (diff) | |
parent | 64bee4d28c9e2296f4f12a6c4cc40d085c2c9534 (diff) |
Merge branch 'acpi-enumeration'
* acpi-enumeration:
spi / ACPI: add ACPI enumeration support
gpio / ACPI: add ACPI support
-rw-r--r-- | drivers/gpio/Kconfig | 4 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 54 | ||||
-rw-r--r-- | drivers/spi/spi.c | 103 | ||||
-rw-r--r-- | include/linux/acpi_gpio.h | 19 |
5 files changed, 180 insertions, 1 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 47150f5ded0..f16557690cf 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -49,6 +49,10 @@ config OF_GPIO | |||
49 | def_bool y | 49 | def_bool y |
50 | depends on OF | 50 | depends on OF |
51 | 51 | ||
52 | config GPIO_ACPI | ||
53 | def_bool y | ||
54 | depends on ACPI | ||
55 | |||
52 | config DEBUG_GPIO | 56 | config DEBUG_GPIO |
53 | bool "Debug GPIO calls" | 57 | bool "Debug GPIO calls" |
54 | depends on DEBUG_KERNEL | 58 | depends on DEBUG_KERNEL |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed670732..420dbaca05f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG | |||
4 | 4 | ||
5 | obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o | 5 | obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o |
6 | obj-$(CONFIG_OF_GPIO) += gpiolib-of.o | 6 | obj-$(CONFIG_OF_GPIO) += gpiolib-of.o |
7 | obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o | ||
7 | 8 | ||
8 | # Device drivers. Generally keep list sorted alphabetically | 9 | # Device drivers. Generally keep list sorted alphabetically |
9 | obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o | 10 | obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o |
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c new file mode 100644 index 00000000000..cbad6e908d3 --- /dev/null +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * ACPI helpers for GPIO API | ||
3 | * | ||
4 | * Copyright (C) 2012, Intel Corporation | ||
5 | * Authors: Mathias Nyman <mathias.nyman@linux.intel.com> | ||
6 | * Mika Westerberg <mika.westerberg@linux.intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/gpio.h> | ||
15 | #include <linux/export.h> | ||
16 | #include <linux/acpi_gpio.h> | ||
17 | #include <linux/acpi.h> | ||
18 | |||
19 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) | ||
20 | { | ||
21 | if (!gc->dev) | ||
22 | return false; | ||
23 | |||
24 | return ACPI_HANDLE(gc->dev) == data; | ||
25 | } | ||
26 | |||
27 | /** | ||
28 | * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API | ||
29 | * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") | ||
30 | * @pin: ACPI GPIO pin number (0-based, controller-relative) | ||
31 | * | ||
32 | * Returns GPIO number to use with Linux generic GPIO API, or errno error value | ||
33 | */ | ||
34 | |||
35 | int acpi_get_gpio(char *path, int pin) | ||
36 | { | ||
37 | struct gpio_chip *chip; | ||
38 | acpi_handle handle; | ||
39 | acpi_status status; | ||
40 | |||
41 | status = acpi_get_handle(NULL, path, &handle); | ||
42 | if (ACPI_FAILURE(status)) | ||
43 | return -ENODEV; | ||
44 | |||
45 | chip = gpiochip_find(handle, acpi_gpiochip_find); | ||
46 | if (!chip) | ||
47 | return -ENODEV; | ||
48 | |||
49 | if (!gpio_is_valid(chip->base + pin)) | ||
50 | return -EINVAL; | ||
51 | |||
52 | return chip->base + pin; | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(acpi_get_gpio); | ||
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 84c2861d6f4..1ab05234729 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
37 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
38 | #include <linux/ioport.h> | ||
39 | #include <linux/acpi.h> | ||
38 | 40 | ||
39 | static void spidev_release(struct device *dev) | 41 | static void spidev_release(struct device *dev) |
40 | { | 42 | { |
@@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) | |||
93 | if (of_driver_match_device(dev, drv)) | 95 | if (of_driver_match_device(dev, drv)) |
94 | return 1; | 96 | return 1; |
95 | 97 | ||
98 | /* Then try ACPI */ | ||
99 | if (acpi_driver_match_device(dev, drv)) | ||
100 | return 1; | ||
101 | |||
96 | if (sdrv->id_table) | 102 | if (sdrv->id_table) |
97 | return !!spi_match_id(sdrv->id_table, spi); | 103 | return !!spi_match_id(sdrv->id_table, spi); |
98 | 104 | ||
@@ -888,6 +894,100 @@ static void of_register_spi_devices(struct spi_master *master) | |||
888 | static void of_register_spi_devices(struct spi_master *master) { } | 894 | static void of_register_spi_devices(struct spi_master *master) { } |
889 | #endif | 895 | #endif |
890 | 896 | ||
897 | #ifdef CONFIG_ACPI | ||
898 | static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) | ||
899 | { | ||
900 | struct spi_device *spi = data; | ||
901 | |||
902 | if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { | ||
903 | struct acpi_resource_spi_serialbus *sb; | ||
904 | |||
905 | sb = &ares->data.spi_serial_bus; | ||
906 | if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { | ||
907 | spi->chip_select = sb->device_selection; | ||
908 | spi->max_speed_hz = sb->connection_speed; | ||
909 | |||
910 | if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) | ||
911 | spi->mode |= SPI_CPHA; | ||
912 | if (sb->clock_polarity == ACPI_SPI_START_HIGH) | ||
913 | spi->mode |= SPI_CPOL; | ||
914 | if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) | ||
915 | spi->mode |= SPI_CS_HIGH; | ||
916 | } | ||
917 | } else if (spi->irq < 0) { | ||
918 | struct resource r; | ||
919 | |||
920 | if (acpi_dev_resource_interrupt(ares, 0, &r)) | ||
921 | spi->irq = r.start; | ||
922 | } | ||
923 | |||
924 | /* Always tell the ACPI core to skip this resource */ | ||
925 | return 1; | ||
926 | } | ||
927 | |||
928 | static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, | ||
929 | void *data, void **return_value) | ||
930 | { | ||
931 | struct spi_master *master = data; | ||
932 | struct list_head resource_list; | ||
933 | struct acpi_device *adev; | ||
934 | struct spi_device *spi; | ||
935 | int ret; | ||
936 | |||
937 | if (acpi_bus_get_device(handle, &adev)) | ||
938 | return AE_OK; | ||
939 | if (acpi_bus_get_status(adev) || !adev->status.present) | ||
940 | return AE_OK; | ||
941 | |||
942 | spi = spi_alloc_device(master); | ||
943 | if (!spi) { | ||
944 | dev_err(&master->dev, "failed to allocate SPI device for %s\n", | ||
945 | dev_name(&adev->dev)); | ||
946 | return AE_NO_MEMORY; | ||
947 | } | ||
948 | |||
949 | ACPI_HANDLE_SET(&spi->dev, handle); | ||
950 | spi->irq = -1; | ||
951 | |||
952 | INIT_LIST_HEAD(&resource_list); | ||
953 | ret = acpi_dev_get_resources(adev, &resource_list, | ||
954 | acpi_spi_add_resource, spi); | ||
955 | acpi_dev_free_resource_list(&resource_list); | ||
956 | |||
957 | if (ret < 0 || !spi->max_speed_hz) { | ||
958 | spi_dev_put(spi); | ||
959 | return AE_OK; | ||
960 | } | ||
961 | |||
962 | strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); | ||
963 | if (spi_add_device(spi)) { | ||
964 | dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", | ||
965 | dev_name(&adev->dev)); | ||
966 | spi_dev_put(spi); | ||
967 | } | ||
968 | |||
969 | return AE_OK; | ||
970 | } | ||
971 | |||
972 | static void acpi_register_spi_devices(struct spi_master *master) | ||
973 | { | ||
974 | acpi_status status; | ||
975 | acpi_handle handle; | ||
976 | |||
977 | handle = ACPI_HANDLE(&master->dev); | ||
978 | if (!handle) | ||
979 | return; | ||
980 | |||
981 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, | ||
982 | acpi_spi_add_device, NULL, | ||
983 | master, NULL); | ||
984 | if (ACPI_FAILURE(status)) | ||
985 | dev_warn(&master->dev, "failed to enumerate SPI slaves\n"); | ||
986 | } | ||
987 | #else | ||
988 | static inline void acpi_register_spi_devices(struct spi_master *master) {} | ||
989 | #endif /* CONFIG_ACPI */ | ||
990 | |||
891 | static void spi_master_release(struct device *dev) | 991 | static void spi_master_release(struct device *dev) |
892 | { | 992 | { |
893 | struct spi_master *master; | 993 | struct spi_master *master; |
@@ -1023,8 +1123,9 @@ int spi_register_master(struct spi_master *master) | |||
1023 | spi_match_master_to_boardinfo(master, &bi->board_info); | 1123 | spi_match_master_to_boardinfo(master, &bi->board_info); |
1024 | mutex_unlock(&board_lock); | 1124 | mutex_unlock(&board_lock); |
1025 | 1125 | ||
1026 | /* Register devices from the device tree */ | 1126 | /* Register devices from the device tree and ACPI */ |
1027 | of_register_spi_devices(master); | 1127 | of_register_spi_devices(master); |
1128 | acpi_register_spi_devices(master); | ||
1028 | done: | 1129 | done: |
1029 | return status; | 1130 | return status; |
1030 | } | 1131 | } |
diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h new file mode 100644 index 00000000000..91615a389b6 --- /dev/null +++ b/include/linux/acpi_gpio.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef _LINUX_ACPI_GPIO_H_ | ||
2 | #define _LINUX_ACPI_GPIO_H_ | ||
3 | |||
4 | #include <linux/errno.h> | ||
5 | |||
6 | #ifdef CONFIG_GPIO_ACPI | ||
7 | |||
8 | int acpi_get_gpio(char *path, int pin); | ||
9 | |||
10 | #else /* CONFIG_GPIO_ACPI */ | ||
11 | |||
12 | static inline int acpi_get_gpio(char *path, int pin) | ||
13 | { | ||
14 | return -ENODEV; | ||
15 | } | ||
16 | |||
17 | #endif /* CONFIG_GPIO_ACPI */ | ||
18 | |||
19 | #endif /* _LINUX_ACPI_GPIO_H_ */ | ||