1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Kontron PLD MFD core driver |
4 | * |
5 | * Copyright (c) 2010-2013 Kontron Europe GmbH |
6 | * Author: Michael Brunner <michael.brunner@kontron.com> |
7 | */ |
8 | |
9 | #include <linux/platform_device.h> |
10 | #include <linux/mfd/core.h> |
11 | #include <linux/mfd/kempld.h> |
12 | #include <linux/module.h> |
13 | #include <linux/dmi.h> |
14 | #include <linux/io.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/acpi.h> |
17 | |
18 | #define MAX_ID_LEN 4 |
19 | static char force_device_id[MAX_ID_LEN + 1] = "" ; |
20 | module_param_string(force_device_id, force_device_id, |
21 | sizeof(force_device_id), 0); |
22 | MODULE_PARM_DESC(force_device_id, "Override detected product" ); |
23 | |
24 | /* |
25 | * Get hardware mutex to block firmware from accessing the pld. |
26 | * It is possible for the firmware may hold the mutex for an extended length of |
27 | * time. This function will block until access has been granted. |
28 | */ |
29 | static void kempld_get_hardware_mutex(struct kempld_device_data *pld) |
30 | { |
31 | /* The mutex bit will read 1 until access has been granted */ |
32 | while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY) |
33 | usleep_range(min: 1000, max: 3000); |
34 | } |
35 | |
36 | static void kempld_release_hardware_mutex(struct kempld_device_data *pld) |
37 | { |
38 | /* The harware mutex is released when 1 is written to the mutex bit. */ |
39 | iowrite8(KEMPLD_MUTEX_KEY, pld->io_index); |
40 | } |
41 | |
42 | static int kempld_get_info_generic(struct kempld_device_data *pld) |
43 | { |
44 | u16 version; |
45 | u8 spec; |
46 | |
47 | kempld_get_mutex(pld); |
48 | |
49 | version = kempld_read16(pld, KEMPLD_VERSION); |
50 | spec = kempld_read8(pld, KEMPLD_SPEC); |
51 | pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR); |
52 | |
53 | pld->info.minor = KEMPLD_VERSION_GET_MINOR(version); |
54 | pld->info.major = KEMPLD_VERSION_GET_MAJOR(version); |
55 | pld->info.number = KEMPLD_VERSION_GET_NUMBER(version); |
56 | pld->info.type = KEMPLD_VERSION_GET_TYPE(version); |
57 | |
58 | if (spec == 0xff) { |
59 | pld->info.spec_minor = 0; |
60 | pld->info.spec_major = 1; |
61 | } else { |
62 | pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec); |
63 | pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec); |
64 | } |
65 | |
66 | if (pld->info.spec_major > 0) |
67 | pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE); |
68 | else |
69 | pld->feature_mask = 0; |
70 | |
71 | kempld_release_mutex(pld); |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | enum kempld_cells { |
77 | KEMPLD_I2C = 0, |
78 | KEMPLD_WDT, |
79 | KEMPLD_GPIO, |
80 | KEMPLD_UART, |
81 | }; |
82 | |
83 | static const char *kempld_dev_names[] = { |
84 | [KEMPLD_I2C] = "kempld-i2c" , |
85 | [KEMPLD_WDT] = "kempld-wdt" , |
86 | [KEMPLD_GPIO] = "kempld-gpio" , |
87 | [KEMPLD_UART] = "kempld-uart" , |
88 | }; |
89 | |
90 | #define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_dev_names) |
91 | |
92 | static int kempld_register_cells_generic(struct kempld_device_data *pld) |
93 | { |
94 | struct mfd_cell devs[KEMPLD_MAX_DEVS] = {}; |
95 | int i = 0; |
96 | |
97 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C) |
98 | devs[i++].name = kempld_dev_names[KEMPLD_I2C]; |
99 | |
100 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG) |
101 | devs[i++].name = kempld_dev_names[KEMPLD_WDT]; |
102 | |
103 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO) |
104 | devs[i++].name = kempld_dev_names[KEMPLD_GPIO]; |
105 | |
106 | if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART) |
107 | devs[i++].name = kempld_dev_names[KEMPLD_UART]; |
108 | |
109 | return mfd_add_devices(parent: pld->dev, id: -1, cells: devs, n_devs: i, NULL, irq_base: 0, NULL); |
110 | } |
111 | |
112 | static struct resource kempld_ioresource = { |
113 | .start = KEMPLD_IOINDEX, |
114 | .end = KEMPLD_IODATA, |
115 | .flags = IORESOURCE_IO, |
116 | }; |
117 | |
118 | static const struct kempld_platform_data kempld_platform_data_generic = { |
119 | .pld_clock = KEMPLD_CLK, |
120 | .ioresource = &kempld_ioresource, |
121 | .get_hardware_mutex = kempld_get_hardware_mutex, |
122 | .release_hardware_mutex = kempld_release_hardware_mutex, |
123 | .get_info = kempld_get_info_generic, |
124 | .register_cells = kempld_register_cells_generic, |
125 | }; |
126 | |
127 | static struct platform_device *kempld_pdev; |
128 | |
129 | static int kempld_create_platform_device(const struct dmi_system_id *id) |
130 | { |
131 | const struct kempld_platform_data *pdata = id->driver_data; |
132 | int ret; |
133 | |
134 | kempld_pdev = platform_device_alloc(name: "kempld" , id: -1); |
135 | if (!kempld_pdev) |
136 | return -ENOMEM; |
137 | |
138 | ret = platform_device_add_data(pdev: kempld_pdev, data: pdata, size: sizeof(*pdata)); |
139 | if (ret) |
140 | goto err; |
141 | |
142 | ret = platform_device_add_resources(pdev: kempld_pdev, res: pdata->ioresource, num: 1); |
143 | if (ret) |
144 | goto err; |
145 | |
146 | ret = platform_device_add(pdev: kempld_pdev); |
147 | if (ret) |
148 | goto err; |
149 | |
150 | return 0; |
151 | err: |
152 | platform_device_put(pdev: kempld_pdev); |
153 | return ret; |
154 | } |
155 | |
156 | /** |
157 | * kempld_read8 - read 8 bit register |
158 | * @pld: kempld_device_data structure describing the PLD |
159 | * @index: register index on the chip |
160 | * |
161 | * kempld_get_mutex must be called prior to calling this function. |
162 | */ |
163 | u8 kempld_read8(struct kempld_device_data *pld, u8 index) |
164 | { |
165 | iowrite8(index, pld->io_index); |
166 | return ioread8(pld->io_data); |
167 | } |
168 | EXPORT_SYMBOL_GPL(kempld_read8); |
169 | |
170 | /** |
171 | * kempld_write8 - write 8 bit register |
172 | * @pld: kempld_device_data structure describing the PLD |
173 | * @index: register index on the chip |
174 | * @data: new register value |
175 | * |
176 | * kempld_get_mutex must be called prior to calling this function. |
177 | */ |
178 | void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data) |
179 | { |
180 | iowrite8(index, pld->io_index); |
181 | iowrite8(data, pld->io_data); |
182 | } |
183 | EXPORT_SYMBOL_GPL(kempld_write8); |
184 | |
185 | /** |
186 | * kempld_read16 - read 16 bit register |
187 | * @pld: kempld_device_data structure describing the PLD |
188 | * @index: register index on the chip |
189 | * |
190 | * kempld_get_mutex must be called prior to calling this function. |
191 | */ |
192 | u16 kempld_read16(struct kempld_device_data *pld, u8 index) |
193 | { |
194 | return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8; |
195 | } |
196 | EXPORT_SYMBOL_GPL(kempld_read16); |
197 | |
198 | /** |
199 | * kempld_write16 - write 16 bit register |
200 | * @pld: kempld_device_data structure describing the PLD |
201 | * @index: register index on the chip |
202 | * @data: new register value |
203 | * |
204 | * kempld_get_mutex must be called prior to calling this function. |
205 | */ |
206 | void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data) |
207 | { |
208 | kempld_write8(pld, index, (u8)data); |
209 | kempld_write8(pld, index + 1, (u8)(data >> 8)); |
210 | } |
211 | EXPORT_SYMBOL_GPL(kempld_write16); |
212 | |
213 | /** |
214 | * kempld_read32 - read 32 bit register |
215 | * @pld: kempld_device_data structure describing the PLD |
216 | * @index: register index on the chip |
217 | * |
218 | * kempld_get_mutex must be called prior to calling this function. |
219 | */ |
220 | u32 kempld_read32(struct kempld_device_data *pld, u8 index) |
221 | { |
222 | return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16; |
223 | } |
224 | EXPORT_SYMBOL_GPL(kempld_read32); |
225 | |
226 | /** |
227 | * kempld_write32 - write 32 bit register |
228 | * @pld: kempld_device_data structure describing the PLD |
229 | * @index: register index on the chip |
230 | * @data: new register value |
231 | * |
232 | * kempld_get_mutex must be called prior to calling this function. |
233 | */ |
234 | void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data) |
235 | { |
236 | kempld_write16(pld, index, (u16)data); |
237 | kempld_write16(pld, index + 2, (u16)(data >> 16)); |
238 | } |
239 | EXPORT_SYMBOL_GPL(kempld_write32); |
240 | |
241 | /** |
242 | * kempld_get_mutex - acquire PLD mutex |
243 | * @pld: kempld_device_data structure describing the PLD |
244 | */ |
245 | void kempld_get_mutex(struct kempld_device_data *pld) |
246 | { |
247 | const struct kempld_platform_data *pdata = dev_get_platdata(dev: pld->dev); |
248 | |
249 | mutex_lock(&pld->lock); |
250 | pdata->get_hardware_mutex(pld); |
251 | } |
252 | EXPORT_SYMBOL_GPL(kempld_get_mutex); |
253 | |
254 | /** |
255 | * kempld_release_mutex - release PLD mutex |
256 | * @pld: kempld_device_data structure describing the PLD |
257 | */ |
258 | void kempld_release_mutex(struct kempld_device_data *pld) |
259 | { |
260 | const struct kempld_platform_data *pdata = dev_get_platdata(dev: pld->dev); |
261 | |
262 | pdata->release_hardware_mutex(pld); |
263 | mutex_unlock(lock: &pld->lock); |
264 | } |
265 | EXPORT_SYMBOL_GPL(kempld_release_mutex); |
266 | |
267 | /** |
268 | * kempld_get_info - update device specific information |
269 | * @pld: kempld_device_data structure describing the PLD |
270 | * |
271 | * This function calls the configured board specific kempld_get_info_XXXX |
272 | * function which is responsible for gathering information about the specific |
273 | * hardware. The information is then stored within the pld structure. |
274 | */ |
275 | static int kempld_get_info(struct kempld_device_data *pld) |
276 | { |
277 | int ret; |
278 | const struct kempld_platform_data *pdata = dev_get_platdata(dev: pld->dev); |
279 | char major, minor; |
280 | |
281 | ret = pdata->get_info(pld); |
282 | if (ret) |
283 | return ret; |
284 | |
285 | /* The Kontron PLD firmware version string has the following format: |
286 | * Pwxy.zzzz |
287 | * P: Fixed |
288 | * w: PLD number - 1 hex digit |
289 | * x: Major version - 1 alphanumerical digit (0-9A-V) |
290 | * y: Minor version - 1 alphanumerical digit (0-9A-V) |
291 | * zzzz: Build number - 4 zero padded hex digits */ |
292 | |
293 | if (pld->info.major < 10) |
294 | major = pld->info.major + '0'; |
295 | else |
296 | major = (pld->info.major - 10) + 'A'; |
297 | if (pld->info.minor < 10) |
298 | minor = pld->info.minor + '0'; |
299 | else |
300 | minor = (pld->info.minor - 10) + 'A'; |
301 | |
302 | ret = scnprintf(buf: pld->info.version, size: sizeof(pld->info.version), |
303 | fmt: "P%X%c%c.%04X" , pld->info.number, major, minor, |
304 | pld->info.buildnr); |
305 | if (ret < 0) |
306 | return ret; |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | /* |
312 | * kempld_register_cells - register cell drivers |
313 | * |
314 | * This function registers cell drivers for the detected hardware by calling |
315 | * the configured kempld_register_cells_XXXX function which is responsible |
316 | * to detect and register the needed cell drivers. |
317 | */ |
318 | static int kempld_register_cells(struct kempld_device_data *pld) |
319 | { |
320 | const struct kempld_platform_data *pdata = dev_get_platdata(dev: pld->dev); |
321 | |
322 | return pdata->register_cells(pld); |
323 | } |
324 | |
325 | static const char *kempld_get_type_string(struct kempld_device_data *pld) |
326 | { |
327 | const char *version_type; |
328 | |
329 | switch (pld->info.type) { |
330 | case 0: |
331 | version_type = "release" ; |
332 | break; |
333 | case 1: |
334 | version_type = "debug" ; |
335 | break; |
336 | case 2: |
337 | version_type = "custom" ; |
338 | break; |
339 | default: |
340 | version_type = "unspecified" ; |
341 | break; |
342 | } |
343 | |
344 | return version_type; |
345 | } |
346 | |
347 | static ssize_t pld_version_show(struct device *dev, |
348 | struct device_attribute *attr, char *buf) |
349 | { |
350 | struct kempld_device_data *pld = dev_get_drvdata(dev); |
351 | |
352 | return sysfs_emit(buf, fmt: "%s\n" , pld->info.version); |
353 | } |
354 | |
355 | static ssize_t pld_specification_show(struct device *dev, |
356 | struct device_attribute *attr, char *buf) |
357 | { |
358 | struct kempld_device_data *pld = dev_get_drvdata(dev); |
359 | |
360 | return sysfs_emit(buf, fmt: "%d.%d\n" , pld->info.spec_major, pld->info.spec_minor); |
361 | } |
362 | |
363 | static ssize_t pld_type_show(struct device *dev, |
364 | struct device_attribute *attr, char *buf) |
365 | { |
366 | struct kempld_device_data *pld = dev_get_drvdata(dev); |
367 | |
368 | return sysfs_emit(buf, fmt: "%s\n" , kempld_get_type_string(pld)); |
369 | } |
370 | |
371 | static DEVICE_ATTR_RO(pld_version); |
372 | static DEVICE_ATTR_RO(pld_specification); |
373 | static DEVICE_ATTR_RO(pld_type); |
374 | |
375 | static struct attribute *pld_attributes[] = { |
376 | &dev_attr_pld_version.attr, |
377 | &dev_attr_pld_specification.attr, |
378 | &dev_attr_pld_type.attr, |
379 | NULL |
380 | }; |
381 | |
382 | static const struct attribute_group pld_attr_group = { |
383 | .attrs = pld_attributes, |
384 | }; |
385 | |
386 | static int kempld_detect_device(struct kempld_device_data *pld) |
387 | { |
388 | u8 index_reg; |
389 | int ret; |
390 | |
391 | mutex_lock(&pld->lock); |
392 | |
393 | /* Check for empty IO space */ |
394 | index_reg = ioread8(pld->io_index); |
395 | if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) { |
396 | mutex_unlock(lock: &pld->lock); |
397 | return -ENODEV; |
398 | } |
399 | |
400 | /* Release hardware mutex if acquired */ |
401 | if (!(index_reg & KEMPLD_MUTEX_KEY)) { |
402 | iowrite8(KEMPLD_MUTEX_KEY, pld->io_index); |
403 | /* PXT and COMe-cPC2 boards may require a second release */ |
404 | iowrite8(KEMPLD_MUTEX_KEY, pld->io_index); |
405 | } |
406 | |
407 | mutex_unlock(lock: &pld->lock); |
408 | |
409 | ret = kempld_get_info(pld); |
410 | if (ret) |
411 | return ret; |
412 | |
413 | dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n" , |
414 | pld->info.version, kempld_get_type_string(pld), |
415 | pld->info.spec_major, pld->info.spec_minor); |
416 | |
417 | ret = sysfs_create_group(kobj: &pld->dev->kobj, grp: &pld_attr_group); |
418 | if (ret) |
419 | return ret; |
420 | |
421 | ret = kempld_register_cells(pld); |
422 | if (ret) |
423 | sysfs_remove_group(kobj: &pld->dev->kobj, grp: &pld_attr_group); |
424 | |
425 | return ret; |
426 | } |
427 | |
428 | #ifdef CONFIG_ACPI |
429 | static int kempld_get_acpi_data(struct platform_device *pdev) |
430 | { |
431 | struct list_head resource_list; |
432 | struct resource *resources; |
433 | struct resource_entry *rentry; |
434 | struct device *dev = &pdev->dev; |
435 | struct acpi_device *acpi_dev = ACPI_COMPANION(dev); |
436 | const struct kempld_platform_data *pdata; |
437 | int ret; |
438 | int count; |
439 | |
440 | pdata = acpi_device_get_match_data(dev); |
441 | ret = platform_device_add_data(pdev, data: pdata, |
442 | size: sizeof(struct kempld_platform_data)); |
443 | if (ret) |
444 | return ret; |
445 | |
446 | INIT_LIST_HEAD(list: &resource_list); |
447 | ret = acpi_dev_get_resources(adev: acpi_dev, list: &resource_list, NULL, NULL); |
448 | if (ret < 0) |
449 | goto out; |
450 | |
451 | count = ret; |
452 | |
453 | if (count == 0) { |
454 | ret = platform_device_add_resources(pdev, res: pdata->ioresource, num: 1); |
455 | goto out; |
456 | } |
457 | |
458 | resources = devm_kcalloc(dev: &acpi_dev->dev, n: count, size: sizeof(*resources), |
459 | GFP_KERNEL); |
460 | if (!resources) { |
461 | ret = -ENOMEM; |
462 | goto out; |
463 | } |
464 | |
465 | count = 0; |
466 | list_for_each_entry(rentry, &resource_list, node) { |
467 | memcpy(&resources[count], rentry->res, |
468 | sizeof(*resources)); |
469 | count++; |
470 | } |
471 | ret = platform_device_add_resources(pdev, res: resources, num: count); |
472 | |
473 | out: |
474 | acpi_dev_free_resource_list(list: &resource_list); |
475 | |
476 | return ret; |
477 | } |
478 | #else |
479 | static int kempld_get_acpi_data(struct platform_device *pdev) |
480 | { |
481 | return -ENODEV; |
482 | } |
483 | #endif /* CONFIG_ACPI */ |
484 | |
485 | static int kempld_probe(struct platform_device *pdev) |
486 | { |
487 | const struct kempld_platform_data *pdata; |
488 | struct device *dev = &pdev->dev; |
489 | struct kempld_device_data *pld; |
490 | struct resource *ioport; |
491 | int ret; |
492 | |
493 | if (kempld_pdev == NULL) { |
494 | /* |
495 | * No kempld_pdev device has been registered in kempld_init, |
496 | * so we seem to be probing an ACPI platform device. |
497 | */ |
498 | ret = kempld_get_acpi_data(pdev); |
499 | if (ret) |
500 | return ret; |
501 | } else if (kempld_pdev != pdev) { |
502 | /* |
503 | * The platform device we are probing is not the one we |
504 | * registered in kempld_init using the DMI table, so this one |
505 | * comes from ACPI. |
506 | * As we can only probe one - abort here and use the DMI |
507 | * based one instead. |
508 | */ |
509 | dev_notice(dev, "platform device exists - not using ACPI\n" ); |
510 | return -ENODEV; |
511 | } |
512 | pdata = dev_get_platdata(dev); |
513 | |
514 | pld = devm_kzalloc(dev, size: sizeof(*pld), GFP_KERNEL); |
515 | if (!pld) |
516 | return -ENOMEM; |
517 | |
518 | ioport = platform_get_resource(pdev, IORESOURCE_IO, 0); |
519 | if (!ioport) |
520 | return -EINVAL; |
521 | |
522 | pld->io_base = devm_ioport_map(dev, port: ioport->start, |
523 | nr: resource_size(res: ioport)); |
524 | if (!pld->io_base) |
525 | return -ENOMEM; |
526 | |
527 | pld->io_index = pld->io_base; |
528 | pld->io_data = pld->io_base + 1; |
529 | pld->pld_clock = pdata->pld_clock; |
530 | pld->dev = dev; |
531 | |
532 | mutex_init(&pld->lock); |
533 | platform_set_drvdata(pdev, data: pld); |
534 | |
535 | return kempld_detect_device(pld); |
536 | } |
537 | |
538 | static int kempld_remove(struct platform_device *pdev) |
539 | { |
540 | struct kempld_device_data *pld = platform_get_drvdata(pdev); |
541 | const struct kempld_platform_data *pdata = dev_get_platdata(dev: pld->dev); |
542 | |
543 | sysfs_remove_group(kobj: &pld->dev->kobj, grp: &pld_attr_group); |
544 | |
545 | mfd_remove_devices(parent: &pdev->dev); |
546 | pdata->release_hardware_mutex(pld); |
547 | |
548 | return 0; |
549 | } |
550 | |
551 | #ifdef CONFIG_ACPI |
552 | static const struct acpi_device_id kempld_acpi_table[] = { |
553 | { "KEM0000" , (kernel_ulong_t)&kempld_platform_data_generic }, |
554 | { "KEM0001" , (kernel_ulong_t)&kempld_platform_data_generic }, |
555 | {} |
556 | }; |
557 | MODULE_DEVICE_TABLE(acpi, kempld_acpi_table); |
558 | #endif |
559 | |
560 | static struct platform_driver kempld_driver = { |
561 | .driver = { |
562 | .name = "kempld" , |
563 | .acpi_match_table = ACPI_PTR(kempld_acpi_table), |
564 | }, |
565 | .probe = kempld_probe, |
566 | .remove = kempld_remove, |
567 | }; |
568 | |
569 | static const struct dmi_system_id kempld_dmi_table[] __initconst = { |
570 | { |
571 | .ident = "BBD6" , |
572 | .matches = { |
573 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
574 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD" ), |
575 | }, |
576 | .driver_data = (void *)&kempld_platform_data_generic, |
577 | .callback = kempld_create_platform_device, |
578 | }, { |
579 | .ident = "BBL6" , |
580 | .matches = { |
581 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
582 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6" ), |
583 | }, |
584 | .driver_data = (void *)&kempld_platform_data_generic, |
585 | .callback = kempld_create_platform_device, |
586 | }, { |
587 | .ident = "BDV7" , |
588 | .matches = { |
589 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
590 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bDV7" ), |
591 | }, |
592 | .driver_data = (void *)&kempld_platform_data_generic, |
593 | .callback = kempld_create_platform_device, |
594 | }, { |
595 | .ident = "BHL6" , |
596 | .matches = { |
597 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
598 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6" ), |
599 | }, |
600 | .driver_data = (void *)&kempld_platform_data_generic, |
601 | .callback = kempld_create_platform_device, |
602 | }, { |
603 | .ident = "BKL6" , |
604 | .matches = { |
605 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
606 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6" ), |
607 | }, |
608 | .driver_data = (void *)&kempld_platform_data_generic, |
609 | .callback = kempld_create_platform_device, |
610 | }, { |
611 | .ident = "BSL6" , |
612 | .matches = { |
613 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
614 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6" ), |
615 | }, |
616 | .driver_data = (void *)&kempld_platform_data_generic, |
617 | .callback = kempld_create_platform_device, |
618 | }, { |
619 | .ident = "CAL6" , |
620 | .matches = { |
621 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
622 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL" ), |
623 | }, |
624 | .driver_data = (void *)&kempld_platform_data_generic, |
625 | .callback = kempld_create_platform_device, |
626 | }, { |
627 | .ident = "CBL6" , |
628 | .matches = { |
629 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
630 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6" ), |
631 | }, |
632 | .driver_data = (void *)&kempld_platform_data_generic, |
633 | .callback = kempld_create_platform_device, |
634 | }, { |
635 | .ident = "CBW6" , |
636 | .matches = { |
637 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
638 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6" ), |
639 | }, |
640 | .driver_data = (void *)&kempld_platform_data_generic, |
641 | .callback = kempld_create_platform_device, |
642 | }, { |
643 | .ident = "CCR2" , |
644 | .matches = { |
645 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
646 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2" ), |
647 | }, |
648 | .driver_data = (void *)&kempld_platform_data_generic, |
649 | .callback = kempld_create_platform_device, |
650 | }, { |
651 | .ident = "CCR6" , |
652 | .matches = { |
653 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
654 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6" ), |
655 | }, |
656 | .driver_data = (void *)&kempld_platform_data_generic, |
657 | .callback = kempld_create_platform_device, |
658 | }, { |
659 | .ident = "CDV7" , |
660 | .matches = { |
661 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
662 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cDV7" ), |
663 | }, |
664 | .driver_data = (void *)&kempld_platform_data_generic, |
665 | .callback = kempld_create_platform_device, |
666 | }, { |
667 | .ident = "CHL6" , |
668 | .matches = { |
669 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
670 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6" ), |
671 | }, |
672 | .driver_data = (void *)&kempld_platform_data_generic, |
673 | .callback = kempld_create_platform_device, |
674 | }, { |
675 | .ident = "CHR2" , |
676 | .matches = { |
677 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
678 | DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2" ), |
679 | }, |
680 | .driver_data = (void *)&kempld_platform_data_generic, |
681 | .callback = kempld_create_platform_device, |
682 | }, { |
683 | .ident = "CHR2" , |
684 | .matches = { |
685 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
686 | DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2" ), |
687 | }, |
688 | .driver_data = (void *)&kempld_platform_data_generic, |
689 | .callback = kempld_create_platform_device, |
690 | }, { |
691 | .ident = "CHR2" , |
692 | .matches = { |
693 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
694 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2" ), |
695 | }, |
696 | .driver_data = (void *)&kempld_platform_data_generic, |
697 | .callback = kempld_create_platform_device, |
698 | }, { |
699 | .ident = "CHR6" , |
700 | .matches = { |
701 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
702 | DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6" ), |
703 | }, |
704 | .driver_data = (void *)&kempld_platform_data_generic, |
705 | .callback = kempld_create_platform_device, |
706 | }, { |
707 | .ident = "CHR6" , |
708 | .matches = { |
709 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
710 | DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6" ), |
711 | }, |
712 | .driver_data = (void *)&kempld_platform_data_generic, |
713 | .callback = kempld_create_platform_device, |
714 | }, { |
715 | .ident = "CHR6" , |
716 | .matches = { |
717 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
718 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6" ), |
719 | }, |
720 | .driver_data = (void *)&kempld_platform_data_generic, |
721 | .callback = kempld_create_platform_device, |
722 | }, { |
723 | .ident = "CKL6" , |
724 | .matches = { |
725 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
726 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6" ), |
727 | }, |
728 | .driver_data = (void *)&kempld_platform_data_generic, |
729 | .callback = kempld_create_platform_device, |
730 | }, { |
731 | .ident = "CNTG" , |
732 | .matches = { |
733 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
734 | DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC" ), |
735 | }, |
736 | .driver_data = (void *)&kempld_platform_data_generic, |
737 | .callback = kempld_create_platform_device, |
738 | }, { |
739 | .ident = "CNTG" , |
740 | .matches = { |
741 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
742 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2" ), |
743 | }, |
744 | .driver_data = (void *)&kempld_platform_data_generic, |
745 | .callback = kempld_create_platform_device, |
746 | }, { |
747 | .ident = "CNTX" , |
748 | .matches = { |
749 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
750 | DMI_MATCH(DMI_BOARD_NAME, "PXT" ), |
751 | }, |
752 | .driver_data = (void *)&kempld_platform_data_generic, |
753 | .callback = kempld_create_platform_device, |
754 | }, { |
755 | .ident = "CSL6" , |
756 | .matches = { |
757 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
758 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6" ), |
759 | }, |
760 | .driver_data = (void *)&kempld_platform_data_generic, |
761 | .callback = kempld_create_platform_device, |
762 | }, { |
763 | .ident = "CVV6" , |
764 | .matches = { |
765 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
766 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT" ), |
767 | }, |
768 | .driver_data = (void *)&kempld_platform_data_generic, |
769 | .callback = kempld_create_platform_device, |
770 | }, { |
771 | .ident = "FRI2" , |
772 | .matches = { |
773 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
774 | DMI_MATCH(DMI_BIOS_VERSION, "FRI2" ), |
775 | }, |
776 | .driver_data = (void *)&kempld_platform_data_generic, |
777 | .callback = kempld_create_platform_device, |
778 | }, { |
779 | .ident = "FRI2" , |
780 | .matches = { |
781 | DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II" ), |
782 | }, |
783 | .driver_data = (void *)&kempld_platform_data_generic, |
784 | .callback = kempld_create_platform_device, |
785 | }, { |
786 | .ident = "A203" , |
787 | .matches = { |
788 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
789 | DMI_MATCH(DMI_BOARD_NAME, "KBox A-203" ), |
790 | }, |
791 | .driver_data = (void *)&kempld_platform_data_generic, |
792 | .callback = kempld_create_platform_device, |
793 | }, { |
794 | .ident = "M4A1" , |
795 | .matches = { |
796 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
797 | DMI_MATCH(DMI_BOARD_NAME, "COMe-m4AL" ), |
798 | }, |
799 | .driver_data = (void *)&kempld_platform_data_generic, |
800 | .callback = kempld_create_platform_device, |
801 | }, { |
802 | .ident = "MAL1" , |
803 | .matches = { |
804 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
805 | DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10" ), |
806 | }, |
807 | .driver_data = (void *)&kempld_platform_data_generic, |
808 | .callback = kempld_create_platform_device, |
809 | }, { |
810 | .ident = "MAPL" , |
811 | .matches = { |
812 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
813 | DMI_MATCH(DMI_BOARD_NAME, "mITX-APL" ), |
814 | }, |
815 | .driver_data = (void *)&kempld_platform_data_generic, |
816 | .callback = kempld_create_platform_device, |
817 | }, { |
818 | .ident = "MBR1" , |
819 | .matches = { |
820 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
821 | DMI_MATCH(DMI_BOARD_NAME, "ETX-OH" ), |
822 | }, |
823 | .driver_data = (void *)&kempld_platform_data_generic, |
824 | .callback = kempld_create_platform_device, |
825 | }, { |
826 | .ident = "MVV1" , |
827 | .matches = { |
828 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
829 | DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT" ), |
830 | }, |
831 | .driver_data = (void *)&kempld_platform_data_generic, |
832 | .callback = kempld_create_platform_device, |
833 | }, { |
834 | .ident = "NTC1" , |
835 | .matches = { |
836 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
837 | DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT" ), |
838 | }, |
839 | .driver_data = (void *)&kempld_platform_data_generic, |
840 | .callback = kempld_create_platform_device, |
841 | }, { |
842 | .ident = "NTC1" , |
843 | .matches = { |
844 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
845 | DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT" ), |
846 | }, |
847 | .driver_data = (void *)&kempld_platform_data_generic, |
848 | .callback = kempld_create_platform_device, |
849 | }, { |
850 | .ident = "NTC1" , |
851 | .matches = { |
852 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
853 | DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT" ), |
854 | }, |
855 | .driver_data = (void *)&kempld_platform_data_generic, |
856 | .callback = kempld_create_platform_device, |
857 | }, { |
858 | .ident = "NUP1" , |
859 | .matches = { |
860 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
861 | DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT" ), |
862 | }, |
863 | .driver_data = (void *)&kempld_platform_data_generic, |
864 | .callback = kempld_create_platform_device, |
865 | }, { |
866 | .ident = "PAPL" , |
867 | .matches = { |
868 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
869 | DMI_MATCH(DMI_BOARD_NAME, "pITX-APL" ), |
870 | }, |
871 | .driver_data = (void *)&kempld_platform_data_generic, |
872 | .callback = kempld_create_platform_device, |
873 | }, { |
874 | .ident = "SXAL" , |
875 | .matches = { |
876 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
877 | DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXAL" ), |
878 | }, |
879 | .driver_data = (void *)&kempld_platform_data_generic, |
880 | .callback = kempld_create_platform_device, |
881 | }, { |
882 | .ident = "SXAL4" , |
883 | .matches = { |
884 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
885 | DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXA4" ), |
886 | }, |
887 | .driver_data = (void *)&kempld_platform_data_generic, |
888 | .callback = kempld_create_platform_device, |
889 | }, { |
890 | .ident = "UNP1" , |
891 | .matches = { |
892 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
893 | DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC" ), |
894 | }, |
895 | .driver_data = (void *)&kempld_platform_data_generic, |
896 | .callback = kempld_create_platform_device, |
897 | }, { |
898 | .ident = "UNP1" , |
899 | .matches = { |
900 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
901 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2" ), |
902 | }, |
903 | .driver_data = (void *)&kempld_platform_data_generic, |
904 | .callback = kempld_create_platform_device, |
905 | }, { |
906 | .ident = "UNTG" , |
907 | .matches = { |
908 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
909 | DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC" ), |
910 | }, |
911 | .driver_data = (void *)&kempld_platform_data_generic, |
912 | .callback = kempld_create_platform_device, |
913 | }, { |
914 | .ident = "UNTG" , |
915 | .matches = { |
916 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
917 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2" ), |
918 | }, |
919 | .driver_data = (void *)&kempld_platform_data_generic, |
920 | .callback = kempld_create_platform_device, |
921 | }, { |
922 | .ident = "UUP6" , |
923 | .matches = { |
924 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
925 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6" ), |
926 | }, |
927 | .driver_data = (void *)&kempld_platform_data_generic, |
928 | .callback = kempld_create_platform_device, |
929 | }, { |
930 | .ident = "UTH6" , |
931 | .matches = { |
932 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
933 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6" ), |
934 | }, |
935 | .driver_data = (void *)&kempld_platform_data_generic, |
936 | .callback = kempld_create_platform_device, |
937 | }, { |
938 | .ident = "Q7AL" , |
939 | .matches = { |
940 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron" ), |
941 | DMI_MATCH(DMI_BOARD_NAME, "Qseven-Q7AL" ), |
942 | }, |
943 | .driver_data = (void *)&kempld_platform_data_generic, |
944 | .callback = kempld_create_platform_device, |
945 | }, |
946 | {} |
947 | }; |
948 | MODULE_DEVICE_TABLE(dmi, kempld_dmi_table); |
949 | |
950 | static int __init kempld_init(void) |
951 | { |
952 | const struct dmi_system_id *id; |
953 | |
954 | if (force_device_id[0]) { |
955 | for (id = kempld_dmi_table; |
956 | id->matches[0].slot != DMI_NONE; id++) |
957 | if (strstr(id->ident, force_device_id)) |
958 | if (id->callback && !id->callback(id)) |
959 | break; |
960 | if (id->matches[0].slot == DMI_NONE) |
961 | return -ENODEV; |
962 | } else { |
963 | dmi_check_system(list: kempld_dmi_table); |
964 | } |
965 | |
966 | return platform_driver_register(&kempld_driver); |
967 | } |
968 | |
969 | static void __exit kempld_exit(void) |
970 | { |
971 | if (kempld_pdev) |
972 | platform_device_unregister(kempld_pdev); |
973 | |
974 | platform_driver_unregister(&kempld_driver); |
975 | } |
976 | |
977 | module_init(kempld_init); |
978 | module_exit(kempld_exit); |
979 | |
980 | MODULE_DESCRIPTION("KEM PLD Core Driver" ); |
981 | MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>" ); |
982 | MODULE_LICENSE("GPL" ); |
983 | MODULE_ALIAS("platform:kempld-core" ); |
984 | |