1 // SPDX-License-Identifier: GPL-2.0-only
3 * Kontron PLD MFD core driver
5 * Copyright (c) 2010-2013 Kontron Europe GmbH
6 * Author: Michael Brunner <michael.brunner@kontron.com>
10 #include <linux/platform_device.h>
11 #include <linux/mfd/core.h>
12 #include <linux/mfd/kempld.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/module.h>
15 #include <linux/property.h>
16 #include <linux/dmi.h>
18 #include <linux/delay.h>
19 #include <linux/sysfs.h>
22 static char force_device_id[MAX_ID_LEN + 1] = "";
23 module_param_string(force_device_id, force_device_id,
24 sizeof(force_device_id), 0);
25 MODULE_PARM_DESC(force_device_id, "Override detected product");
28 * Get hardware mutex to block firmware from accessing the pld.
29 * It is possible for the firmware may hold the mutex for an extended length of
30 * time. This function will block until access has been granted.
32 static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
34 /* The mutex bit will read 1 until access has been granted */
35 while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
36 usleep_range(1000, 3000);
39 static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
41 /* The harware mutex is released when 1 is written to the mutex bit. */
42 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
45 static int kempld_get_info_generic(struct kempld_device_data *pld)
50 kempld_get_mutex(pld);
52 version = kempld_read16(pld, KEMPLD_VERSION);
53 spec = kempld_read8(pld, KEMPLD_SPEC);
54 pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
56 pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
57 pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
58 pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
59 pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
62 pld->info.spec_minor = 0;
63 pld->info.spec_major = 1;
65 pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
66 pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
69 if (pld->info.spec_major > 0)
70 pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
72 pld->feature_mask = 0;
74 kempld_release_mutex(pld);
86 static const char *kempld_dev_names[] = {
87 [KEMPLD_I2C] = "kempld-i2c",
88 [KEMPLD_WDT] = "kempld-wdt",
89 [KEMPLD_GPIO] = "kempld-gpio",
90 [KEMPLD_UART] = "kempld-uart",
93 #define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_dev_names)
95 static int kempld_register_cells_generic(struct kempld_device_data *pld)
97 struct mfd_cell devs[KEMPLD_MAX_DEVS] = {};
100 if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
101 devs[i++].name = kempld_dev_names[KEMPLD_I2C];
103 if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
104 devs[i++].name = kempld_dev_names[KEMPLD_WDT];
106 if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
107 devs[i++].name = kempld_dev_names[KEMPLD_GPIO];
109 if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
110 devs[i++].name = kempld_dev_names[KEMPLD_UART];
112 return mfd_add_devices(pld->dev, PLATFORM_DEVID_NONE, devs, i, NULL, 0, NULL);
115 static struct resource kempld_ioresource = {
116 .start = KEMPLD_IOINDEX,
117 .end = KEMPLD_IODATA,
118 .flags = IORESOURCE_IO,
121 static const struct kempld_platform_data kempld_platform_data_generic = {
122 .pld_clock = KEMPLD_CLK,
123 .ioresource = &kempld_ioresource,
124 .get_hardware_mutex = kempld_get_hardware_mutex,
125 .release_hardware_mutex = kempld_release_hardware_mutex,
126 .get_info = kempld_get_info_generic,
127 .register_cells = kempld_register_cells_generic,
130 static struct platform_device *kempld_pdev;
132 static int kempld_create_platform_device(const struct kempld_platform_data *pdata)
134 const struct platform_device_info pdevinfo = {
136 .id = PLATFORM_DEVID_NONE,
137 .res = pdata->ioresource,
140 .size_data = sizeof(*pdata),
143 kempld_pdev = platform_device_register_full(&pdevinfo);
144 if (IS_ERR(kempld_pdev))
145 return PTR_ERR(kempld_pdev);
151 * kempld_read8 - read 8 bit register
152 * @pld: kempld_device_data structure describing the PLD
153 * @index: register index on the chip
155 * kempld_get_mutex must be called prior to calling this function.
157 u8 kempld_read8(struct kempld_device_data *pld, u8 index)
159 iowrite8(index, pld->io_index);
160 return ioread8(pld->io_data);
162 EXPORT_SYMBOL_GPL(kempld_read8);
165 * kempld_write8 - write 8 bit register
166 * @pld: kempld_device_data structure describing the PLD
167 * @index: register index on the chip
168 * @data: new register value
170 * kempld_get_mutex must be called prior to calling this function.
172 void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
174 iowrite8(index, pld->io_index);
175 iowrite8(data, pld->io_data);
177 EXPORT_SYMBOL_GPL(kempld_write8);
180 * kempld_read16 - read 16 bit register
181 * @pld: kempld_device_data structure describing the PLD
182 * @index: register index on the chip
184 * kempld_get_mutex must be called prior to calling this function.
186 u16 kempld_read16(struct kempld_device_data *pld, u8 index)
188 return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
190 EXPORT_SYMBOL_GPL(kempld_read16);
193 * kempld_write16 - write 16 bit register
194 * @pld: kempld_device_data structure describing the PLD
195 * @index: register index on the chip
196 * @data: new register value
198 * kempld_get_mutex must be called prior to calling this function.
200 void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
202 kempld_write8(pld, index, (u8)data);
203 kempld_write8(pld, index + 1, (u8)(data >> 8));
205 EXPORT_SYMBOL_GPL(kempld_write16);
208 * kempld_read32 - read 32 bit register
209 * @pld: kempld_device_data structure describing the PLD
210 * @index: register index on the chip
212 * kempld_get_mutex must be called prior to calling this function.
214 u32 kempld_read32(struct kempld_device_data *pld, u8 index)
216 return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
218 EXPORT_SYMBOL_GPL(kempld_read32);
221 * kempld_write32 - write 32 bit register
222 * @pld: kempld_device_data structure describing the PLD
223 * @index: register index on the chip
224 * @data: new register value
226 * kempld_get_mutex must be called prior to calling this function.
228 void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
230 kempld_write16(pld, index, (u16)data);
231 kempld_write16(pld, index + 2, (u16)(data >> 16));
233 EXPORT_SYMBOL_GPL(kempld_write32);
236 * kempld_get_mutex - acquire PLD mutex
237 * @pld: kempld_device_data structure describing the PLD
239 void kempld_get_mutex(struct kempld_device_data *pld)
241 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
243 mutex_lock(&pld->lock);
244 pdata->get_hardware_mutex(pld);
246 EXPORT_SYMBOL_GPL(kempld_get_mutex);
249 * kempld_release_mutex - release PLD mutex
250 * @pld: kempld_device_data structure describing the PLD
252 void kempld_release_mutex(struct kempld_device_data *pld)
254 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
256 pdata->release_hardware_mutex(pld);
257 mutex_unlock(&pld->lock);
259 EXPORT_SYMBOL_GPL(kempld_release_mutex);
262 * kempld_get_info - update device specific information
263 * @pld: kempld_device_data structure describing the PLD
265 * This function calls the configured board specific kempld_get_info_XXXX
266 * function which is responsible for gathering information about the specific
267 * hardware. The information is then stored within the pld structure.
269 static int kempld_get_info(struct kempld_device_data *pld)
272 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
275 ret = pdata->get_info(pld);
279 /* The Kontron PLD firmware version string has the following format:
282 * w: PLD number - 1 hex digit
283 * x: Major version - 1 alphanumerical digit (0-9A-V)
284 * y: Minor version - 1 alphanumerical digit (0-9A-V)
285 * zzzz: Build number - 4 zero padded hex digits */
287 if (pld->info.major < 10)
288 major = pld->info.major + '0';
290 major = (pld->info.major - 10) + 'A';
291 if (pld->info.minor < 10)
292 minor = pld->info.minor + '0';
294 minor = (pld->info.minor - 10) + 'A';
296 scnprintf(pld->info.version, sizeof(pld->info.version), "P%X%c%c.%04X",
297 pld->info.number, major, minor, pld->info.buildnr);
303 * kempld_register_cells - register cell drivers
305 * This function registers cell drivers for the detected hardware by calling
306 * the configured kempld_register_cells_XXXX function which is responsible
307 * to detect and register the needed cell drivers.
309 static int kempld_register_cells(struct kempld_device_data *pld)
311 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
313 return pdata->register_cells(pld);
316 static const char *kempld_get_type_string(struct kempld_device_data *pld)
318 const char *version_type;
320 switch (pld->info.type) {
322 version_type = "release";
325 version_type = "debug";
328 version_type = "custom";
331 version_type = "unspecified";
338 static ssize_t pld_version_show(struct device *dev,
339 struct device_attribute *attr, char *buf)
341 struct kempld_device_data *pld = dev_get_drvdata(dev);
343 return sysfs_emit(buf, "%s\n", pld->info.version);
346 static ssize_t pld_specification_show(struct device *dev,
347 struct device_attribute *attr, char *buf)
349 struct kempld_device_data *pld = dev_get_drvdata(dev);
351 return sysfs_emit(buf, "%d.%d\n", pld->info.spec_major, pld->info.spec_minor);
354 static ssize_t pld_type_show(struct device *dev,
355 struct device_attribute *attr, char *buf)
357 struct kempld_device_data *pld = dev_get_drvdata(dev);
359 return sysfs_emit(buf, "%s\n", kempld_get_type_string(pld));
362 static DEVICE_ATTR_RO(pld_version);
363 static DEVICE_ATTR_RO(pld_specification);
364 static DEVICE_ATTR_RO(pld_type);
366 static struct attribute *pld_attrs[] = {
367 &dev_attr_pld_version.attr,
368 &dev_attr_pld_specification.attr,
369 &dev_attr_pld_type.attr,
372 ATTRIBUTE_GROUPS(pld);
374 static int kempld_detect_device(struct kempld_device_data *pld)
379 mutex_lock(&pld->lock);
381 /* Check for empty IO space */
382 index_reg = ioread8(pld->io_index);
383 if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
384 mutex_unlock(&pld->lock);
388 /* Release hardware mutex if acquired */
389 if (!(index_reg & KEMPLD_MUTEX_KEY)) {
390 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
391 /* PXT and COMe-cPC2 boards may require a second release */
392 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
395 mutex_unlock(&pld->lock);
397 ret = kempld_get_info(pld);
401 dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
402 pld->info.version, kempld_get_type_string(pld),
403 pld->info.spec_major, pld->info.spec_minor);
405 return kempld_register_cells(pld);
408 static int kempld_probe(struct platform_device *pdev)
410 const struct kempld_platform_data *pdata;
411 struct device *dev = &pdev->dev;
412 struct kempld_device_data *pld;
413 struct resource *ioport;
416 if (IS_ERR_OR_NULL(kempld_pdev)) {
418 * No kempld_pdev device has been registered in kempld_init,
419 * so we seem to be probing an ACPI platform device.
421 pdata = device_get_match_data(dev);
425 ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
428 } else if (kempld_pdev == pdev) {
429 pdata = dev_get_platdata(dev);
432 * The platform device we are probing is not the one we
433 * registered in kempld_init using the DMI table, so this one
435 * As we can only probe one - abort here and use the DMI
438 dev_notice(dev, "platform device exists - not using ACPI\n");
442 pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
446 ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
450 pld->io_base = devm_ioport_map(dev, ioport->start,
451 resource_size(ioport));
455 pld->io_index = pld->io_base;
456 pld->io_data = pld->io_base + 1;
457 pld->pld_clock = pdata->pld_clock;
460 mutex_init(&pld->lock);
461 platform_set_drvdata(pdev, pld);
463 return kempld_detect_device(pld);
466 static void kempld_remove(struct platform_device *pdev)
468 struct kempld_device_data *pld = platform_get_drvdata(pdev);
469 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
471 mfd_remove_devices(&pdev->dev);
472 pdata->release_hardware_mutex(pld);
475 static const struct acpi_device_id kempld_acpi_table[] = {
476 { "KEM0000", (kernel_ulong_t)&kempld_platform_data_generic },
477 { "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic },
480 MODULE_DEVICE_TABLE(acpi, kempld_acpi_table);
482 static struct platform_driver kempld_driver = {
485 .acpi_match_table = kempld_acpi_table,
486 .dev_groups = pld_groups,
488 .probe = kempld_probe,
489 .remove_new = kempld_remove,
492 static const struct dmi_system_id kempld_dmi_table[] __initconst = {
496 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
497 DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"),
502 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
503 DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6"),
508 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
509 DMI_MATCH(DMI_BOARD_NAME, "COMe-bDV7"),
514 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
515 DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
520 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
521 DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"),
526 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
527 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"),
532 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
533 DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"),
538 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
539 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6"),
544 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
545 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6"),
550 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
551 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
556 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
557 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
562 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
563 DMI_MATCH(DMI_BOARD_NAME, "COMe-cDV7"),
568 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
569 DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
574 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
575 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
580 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
581 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
586 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
587 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
592 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
593 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
598 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
599 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
604 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
605 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
610 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
611 DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"),
616 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
617 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
622 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
623 DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
628 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
629 DMI_MATCH(DMI_BOARD_NAME, "PXT"),
634 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
635 DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6"),
640 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
641 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
646 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
647 DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
652 DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
657 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
658 DMI_MATCH(DMI_BOARD_NAME, "KBox A-203"),
663 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
664 DMI_MATCH(DMI_BOARD_NAME, "COMe-m4AL"),
669 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
670 DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10"),
675 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
676 DMI_MATCH(DMI_BOARD_NAME, "mITX-APL"),
681 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
682 DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
687 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
688 DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
693 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
694 DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
699 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
700 DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
705 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
706 DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
711 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
712 DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
717 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
718 DMI_MATCH(DMI_BOARD_NAME, "pITX-APL"),
723 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
724 DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXAL"),
729 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
730 DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXA4"),
735 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
736 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
741 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
742 DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
747 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
748 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
753 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
754 DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
759 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
760 DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
765 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
766 DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
771 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
772 DMI_MATCH(DMI_BOARD_NAME, "Qseven-Q7AL"),
777 MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
779 static int __init kempld_init(void)
781 const struct dmi_system_id *id;
784 for (id = dmi_first_match(kempld_dmi_table); id; id = dmi_first_match(id + 1)) {
785 /* Check, if user asked for the exact device ID match */
786 if (force_device_id[0] && !strstr(id->ident, force_device_id))
789 ret = kempld_create_platform_device(&kempld_platform_data_generic);
798 return platform_driver_register(&kempld_driver);
801 static void __exit kempld_exit(void)
803 platform_device_unregister(kempld_pdev);
804 platform_driver_unregister(&kempld_driver);
807 module_init(kempld_init);
808 module_exit(kempld_exit);
810 MODULE_DESCRIPTION("KEM PLD Core Driver");
811 MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
812 MODULE_LICENSE("GPL");
813 MODULE_ALIAS("platform:kempld-core");