diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2014-10-21 07:33:56 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-04 15:58:21 -0500 |
commit | 733e625139fe455b4d910ac63c18c90f7cbe2d6f (patch) | |
tree | 0c67448b04c118138a66f485094fe951dfe24e84 | |
parent | b31384fa5de37a100507751dfb5c0a49d06cee67 (diff) |
ACPI: Allow drivers to match using Device Tree compatible property
We have lots of existing Device Tree enabled drivers and allocating
separate _HID for each is not feasible. Instead we allocate special _HID
"PRP0001" that means that the match should be done using Device Tree
compatible property using driver's .of_match_table instead if the driver
is missing .acpi_match_table.
If there is a need to distinguish from where the device is enumerated
(DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev).
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Grant Likely <grant.likely@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/property.c | 39 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 106 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 1 | ||||
-rw-r--r-- | include/linux/acpi.h | 8 |
4 files changed, 137 insertions, 17 deletions
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 2541b1fd1fa5..27add91bc270 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c | |||
@@ -76,6 +76,42 @@ static bool acpi_properties_format_valid(const union acpi_object *properties) | |||
76 | return true; | 76 | return true; |
77 | } | 77 | } |
78 | 78 | ||
79 | static void acpi_init_of_compatible(struct acpi_device *adev) | ||
80 | { | ||
81 | const union acpi_object *of_compatible; | ||
82 | struct acpi_hardware_id *hwid; | ||
83 | bool acpi_of = false; | ||
84 | int ret; | ||
85 | |||
86 | /* | ||
87 | * Check if the special PRP0001 ACPI ID is present and in that | ||
88 | * case we fill in Device Tree compatible properties for this | ||
89 | * device. | ||
90 | */ | ||
91 | list_for_each_entry(hwid, &adev->pnp.ids, list) { | ||
92 | if (!strcmp(hwid->id, "PRP0001")) { | ||
93 | acpi_of = true; | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | if (!acpi_of) | ||
99 | return; | ||
100 | |||
101 | ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING, | ||
102 | &of_compatible); | ||
103 | if (ret) { | ||
104 | ret = acpi_dev_get_property(adev, "compatible", | ||
105 | ACPI_TYPE_STRING, &of_compatible); | ||
106 | if (ret) { | ||
107 | acpi_handle_warn(adev->handle, | ||
108 | "PRP0001 requires compatible property\n"); | ||
109 | return; | ||
110 | } | ||
111 | } | ||
112 | adev->data.of_compatible = of_compatible; | ||
113 | } | ||
114 | |||
79 | void acpi_init_properties(struct acpi_device *adev) | 115 | void acpi_init_properties(struct acpi_device *adev) |
80 | { | 116 | { |
81 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; | 117 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; |
@@ -119,6 +155,8 @@ void acpi_init_properties(struct acpi_device *adev) | |||
119 | 155 | ||
120 | adev->data.pointer = buf.pointer; | 156 | adev->data.pointer = buf.pointer; |
121 | adev->data.properties = properties; | 157 | adev->data.properties = properties; |
158 | |||
159 | acpi_init_of_compatible(adev); | ||
122 | return; | 160 | return; |
123 | } | 161 | } |
124 | 162 | ||
@@ -130,6 +168,7 @@ void acpi_init_properties(struct acpi_device *adev) | |||
130 | void acpi_free_properties(struct acpi_device *adev) | 168 | void acpi_free_properties(struct acpi_device *adev) |
131 | { | 169 | { |
132 | ACPI_FREE((void *)adev->data.pointer); | 170 | ACPI_FREE((void *)adev->data.pointer); |
171 | adev->data.of_compatible = NULL; | ||
133 | adev->data.pointer = NULL; | 172 | adev->data.pointer = NULL; |
134 | adev->data.properties = NULL; | 173 | adev->data.properties = NULL; |
135 | } | 174 | } |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 40d80ac0552f..3a8f66444532 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -124,17 +124,56 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, | |||
124 | if (list_empty(&acpi_dev->pnp.ids)) | 124 | if (list_empty(&acpi_dev->pnp.ids)) |
125 | return 0; | 125 | return 0; |
126 | 126 | ||
127 | len = snprintf(modalias, size, "acpi:"); | 127 | /* |
128 | size -= len; | 128 | * If the device has PRP0001 we expose DT compatible modalias |
129 | 129 | * instead in form of of:NnameTCcompatible. | |
130 | list_for_each_entry(id, &acpi_dev->pnp.ids, list) { | 130 | */ |
131 | count = snprintf(&modalias[len], size, "%s:", id->id); | 131 | if (acpi_dev->data.of_compatible) { |
132 | if (count < 0) | 132 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; |
133 | return -EINVAL; | 133 | const union acpi_object *of_compatible, *obj; |
134 | if (count >= size) | 134 | int i, nval; |
135 | return -ENOMEM; | 135 | char *c; |
136 | len += count; | 136 | |
137 | size -= count; | 137 | acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); |
138 | /* DT strings are all in lower case */ | ||
139 | for (c = buf.pointer; *c != '\0'; c++) | ||
140 | *c = tolower(*c); | ||
141 | |||
142 | len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); | ||
143 | ACPI_FREE(buf.pointer); | ||
144 | |||
145 | of_compatible = acpi_dev->data.of_compatible; | ||
146 | if (of_compatible->type == ACPI_TYPE_PACKAGE) { | ||
147 | nval = of_compatible->package.count; | ||
148 | obj = of_compatible->package.elements; | ||
149 | } else { /* Must be ACPI_TYPE_STRING. */ | ||
150 | nval = 1; | ||
151 | obj = of_compatible; | ||
152 | } | ||
153 | for (i = 0; i < nval; i++, obj++) { | ||
154 | count = snprintf(&modalias[len], size, "C%s", | ||
155 | obj->string.pointer); | ||
156 | if (count < 0) | ||
157 | return -EINVAL; | ||
158 | if (count >= size) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | len += count; | ||
162 | size -= count; | ||
163 | } | ||
164 | } else { | ||
165 | len = snprintf(modalias, size, "acpi:"); | ||
166 | size -= len; | ||
167 | |||
168 | list_for_each_entry(id, &acpi_dev->pnp.ids, list) { | ||
169 | count = snprintf(&modalias[len], size, "%s:", id->id); | ||
170 | if (count < 0) | ||
171 | return -EINVAL; | ||
172 | if (count >= size) | ||
173 | return -ENOMEM; | ||
174 | len += count; | ||
175 | size -= count; | ||
176 | } | ||
138 | } | 177 | } |
139 | 178 | ||
140 | modalias[len] = '\0'; | 179 | modalias[len] = '\0'; |
@@ -902,6 +941,51 @@ int acpi_match_device_ids(struct acpi_device *device, | |||
902 | } | 941 | } |
903 | EXPORT_SYMBOL(acpi_match_device_ids); | 942 | EXPORT_SYMBOL(acpi_match_device_ids); |
904 | 943 | ||
944 | /* Performs match against special "PRP0001" shoehorn ACPI ID */ | ||
945 | static bool acpi_of_driver_match_device(struct device *dev, | ||
946 | const struct device_driver *drv) | ||
947 | { | ||
948 | const union acpi_object *of_compatible, *obj; | ||
949 | struct acpi_device *adev; | ||
950 | int i, nval; | ||
951 | |||
952 | adev = ACPI_COMPANION(dev); | ||
953 | if (!adev) | ||
954 | return false; | ||
955 | |||
956 | of_compatible = adev->data.of_compatible; | ||
957 | if (!drv->of_match_table || !of_compatible) | ||
958 | return false; | ||
959 | |||
960 | if (of_compatible->type == ACPI_TYPE_PACKAGE) { | ||
961 | nval = of_compatible->package.count; | ||
962 | obj = of_compatible->package.elements; | ||
963 | } else { /* Must be ACPI_TYPE_STRING. */ | ||
964 | nval = 1; | ||
965 | obj = of_compatible; | ||
966 | } | ||
967 | /* Now we can look for the driver DT compatible strings */ | ||
968 | for (i = 0; i < nval; i++, obj++) { | ||
969 | const struct of_device_id *id; | ||
970 | |||
971 | for (id = drv->of_match_table; id->compatible[0]; id++) | ||
972 | if (!strcasecmp(obj->string.pointer, id->compatible)) | ||
973 | return true; | ||
974 | } | ||
975 | |||
976 | return false; | ||
977 | } | ||
978 | |||
979 | bool acpi_driver_match_device(struct device *dev, | ||
980 | const struct device_driver *drv) | ||
981 | { | ||
982 | if (!drv->acpi_match_table) | ||
983 | return acpi_of_driver_match_device(dev, drv); | ||
984 | |||
985 | return !!acpi_match_device(drv->acpi_match_table, dev); | ||
986 | } | ||
987 | EXPORT_SYMBOL_GPL(acpi_driver_match_device); | ||
988 | |||
905 | static void acpi_free_power_resources_lists(struct acpi_device *device) | 989 | static void acpi_free_power_resources_lists(struct acpi_device *device) |
906 | { | 990 | { |
907 | int i; | 991 | int i; |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 475781170091..f59cbf860658 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -341,6 +341,7 @@ struct acpi_device_physical_node { | |||
341 | struct acpi_device_data { | 341 | struct acpi_device_data { |
342 | const union acpi_object *pointer; | 342 | const union acpi_object *pointer; |
343 | const union acpi_object *properties; | 343 | const union acpi_object *properties; |
344 | const union acpi_object *of_compatible; | ||
344 | }; | 345 | }; |
345 | 346 | ||
346 | /* Device */ | 347 | /* Device */ |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 76d64d6a903a..38296d686c55 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), | |||
424 | const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, | 424 | const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, |
425 | const struct device *dev); | 425 | const struct device *dev); |
426 | 426 | ||
427 | static inline bool acpi_driver_match_device(struct device *dev, | 427 | extern bool acpi_driver_match_device(struct device *dev, |
428 | const struct device_driver *drv) | 428 | const struct device_driver *drv); |
429 | { | ||
430 | return !!acpi_match_device(drv->acpi_match_table, dev); | ||
431 | } | ||
432 | |||
433 | int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); | 429 | int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); |
434 | int acpi_device_modalias(struct device *, char *, int); | 430 | int acpi_device_modalias(struct device *, char *, int); |
435 | 431 | ||