aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Strasser <kevin.strasser@linux.intel.com>2013-06-24 00:00:03 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-06-24 07:48:22 -0400
commit43620a17945b598e707ef897b3866914f9f9056c (patch)
tree67a26eb8bc13e4a2ca0d393b15051eff747cf9ef
parent4124e6e291a7b1a21ea7c28c8f9899d050103308 (diff)
mfd: Kontron PLD mfd driver
Add core MFD driver for the on-board PLD found on some Kontron embedded modules. The PLD device may provide functions like watchdog, GPIO, UART and I2C bus. The following modules are supported: * COMe-bIP# * COMe-bPC2 (ETXexpress-PC) * COMe-bSC# (ETXexpress-SC T#) * COMe-cCT6 * COMe-cDC2 (microETXexpress-DC) * COMe-cPC2 (microETXexpress-PC) * COMe-mCT10 * ETX-OH Originally-From: Michael Brunner <michael.brunner@kontron.com> Signed-off-by: Kevin Strasser <kevin.strasser@linux.intel.com> Acked-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Darren Hart <dvhart@linux.intel.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/mfd/Kconfig21
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/kempld-core.c641
-rw-r--r--include/linux/mfd/kempld.h125
4 files changed, 788 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3e3be603cf82..3bb2932eafb1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -242,6 +242,27 @@ config MFD_JZ4740_ADC
242 Say yes here if you want support for the ADC unit in the JZ4740 SoC. 242 Say yes here if you want support for the ADC unit in the JZ4740 SoC.
243 This driver is necessary for jz4740-battery and jz4740-hwmon driver. 243 This driver is necessary for jz4740-battery and jz4740-hwmon driver.
244 244
245config MFD_KEMPLD
246 tristate "Kontron module PLD device"
247 select MFD_CORE
248 help
249 This is the core driver for the PLD (Programmable Logic Device) found
250 on some Kontron ETX and COMexpress (ETXexpress) modules. The PLD
251 device may provide functions like watchdog, GPIO, UART and I2C bus.
252
253 The following modules are supported:
254 * COMe-bIP#
255 * COMe-bPC2 (ETXexpress-PC)
256 * COMe-bSC# (ETXexpress-SC T#)
257 * COMe-cCT6
258 * COMe-cDC2 (microETXexpress-DC)
259 * COMe-cPC2 (microETXexpress-PC)
260 * COMe-mCT10
261 * ETX-OH
262
263 This driver can also be built as a module. If so, the module
264 will be called kempld-core.
265
245config MFD_88PM800 266config MFD_88PM800
246 tristate "Marvell 88PM800" 267 tristate "Marvell 88PM800"
247 depends on I2C=y && GENERIC_HARDIRQS 268 depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4d70cdb044e0..3c90051ffa5a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
129obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o 129obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
130obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 130obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
131obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 131obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
132obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o
132obj-$(CONFIG_LPC_SCH) += lpc_sch.o 133obj-$(CONFIG_LPC_SCH) += lpc_sch.o
133obj-$(CONFIG_LPC_ICH) += lpc_ich.o 134obj-$(CONFIG_LPC_ICH) += lpc_ich.o
134obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o 135obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
new file mode 100644
index 000000000000..686a4565acb6
--- /dev/null
+++ b/drivers/mfd/kempld-core.c
@@ -0,0 +1,641 @@
1/*
2 * Kontron PLD MFD core driver
3 *
4 * Copyright (c) 2010-2013 Kontron Europe GmbH
5 * Author: Michael Brunner <michael.brunner@kontron.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License 2 as published
9 * by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/platform_device.h>
18#include <linux/mfd/core.h>
19#include <linux/mfd/kempld.h>
20#include <linux/module.h>
21#include <linux/dmi.h>
22#include <linux/io.h>
23#include <linux/delay.h>
24
25#define MAX_ID_LEN 4
26static char force_device_id[MAX_ID_LEN + 1] = "";
27module_param_string(force_device_id, force_device_id, sizeof(force_device_id), 0);
28MODULE_PARM_DESC(force_device_id, "Override detected product");
29
30/*
31 * Get hardware mutex to block firmware from accessing the pld.
32 * It is possible for the firmware may hold the mutex for an extended length of
33 * time. This function will block until access has been granted.
34 */
35static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
36{
37 /* The mutex bit will read 1 until access has been granted */
38 while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
39 msleep(1);
40}
41
42static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
43{
44 /* The harware mutex is released when 1 is written to the mutex bit. */
45 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
46}
47
48static int kempld_get_info_generic(struct kempld_device_data *pld)
49{
50 u16 version;
51 u8 spec;
52
53 kempld_get_mutex(pld);
54
55 version = kempld_read16(pld, KEMPLD_VERSION);
56 spec = kempld_read8(pld, KEMPLD_SPEC);
57 pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
58
59 pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
60 pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
61 pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
62 pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
63
64 if (spec == 0xff) {
65 pld->info.spec_minor = 0;
66 pld->info.spec_major = 1;
67 } else {
68 pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
69 pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
70 }
71
72 if (pld->info.spec_major > 0)
73 pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
74 else
75 pld->feature_mask = 0;
76
77 kempld_release_mutex(pld);
78
79 return 0;
80}
81
82enum kempld_cells {
83 KEMPLD_I2C = 0,
84 KEMPLD_WDT,
85 KEMPLD_GPIO,
86 KEMPLD_UART,
87};
88
89static struct mfd_cell kempld_devs[] = {
90 [KEMPLD_I2C] = {
91 .name = "kempld-i2c",
92 },
93 [KEMPLD_WDT] = {
94 .name = "kempld-wdt",
95 },
96 [KEMPLD_GPIO] = {
97 .name = "kempld-gpio",
98 },
99 [KEMPLD_UART] = {
100 .name = "kempld-uart",
101 },
102};
103
104#define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_devs)
105
106static int kempld_register_cells_generic(struct kempld_device_data *pld)
107{
108 struct mfd_cell devs[KEMPLD_MAX_DEVS];
109 int i = 0;
110
111 if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
112 devs[i++] = kempld_devs[KEMPLD_I2C];
113
114 if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
115 devs[i++] = kempld_devs[KEMPLD_WDT];
116
117 if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
118 devs[i++] = kempld_devs[KEMPLD_GPIO];
119
120 if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
121 devs[i++] = kempld_devs[KEMPLD_UART];
122
123 return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
124}
125
126static struct resource kempld_ioresource = {
127 .start = KEMPLD_IOINDEX,
128 .end = KEMPLD_IODATA,
129 .flags = IORESOURCE_IO,
130};
131
132static const struct kempld_platform_data kempld_platform_data_generic = {
133 .pld_clock = KEMPLD_CLK,
134 .ioresource = &kempld_ioresource,
135 .get_hardware_mutex = kempld_get_hardware_mutex,
136 .release_hardware_mutex = kempld_release_hardware_mutex,
137 .get_info = kempld_get_info_generic,
138 .register_cells = kempld_register_cells_generic,
139};
140
141static struct platform_device *kempld_pdev;
142
143static int kempld_create_platform_device(const struct dmi_system_id *id)
144{
145 struct kempld_platform_data *pdata = id->driver_data;
146 int ret;
147
148 kempld_pdev = platform_device_alloc("kempld", -1);
149 if (!kempld_pdev)
150 return -ENOMEM;
151
152 ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
153 if (ret)
154 goto err;
155
156 ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
157 if (ret)
158 goto err;
159
160 ret = platform_device_add(kempld_pdev);
161 if (ret)
162 goto err;
163
164 return 0;
165err:
166 platform_device_put(kempld_pdev);
167 return ret;
168}
169
170/**
171 * kempld_read8 - read 8 bit register
172 * @pld: kempld_device_data structure describing the PLD
173 * @index: register index on the chip
174 *
175 * kempld_get_mutex must be called prior to calling this function.
176 */
177u8 kempld_read8(struct kempld_device_data *pld, u8 index)
178{
179 iowrite8(index, pld->io_index);
180 return ioread8(pld->io_data);
181}
182EXPORT_SYMBOL_GPL(kempld_read8);
183
184/**
185 * kempld_write8 - write 8 bit register
186 * @pld: kempld_device_data structure describing the PLD
187 * @index: register index on the chip
188 * @data: new register value
189 *
190 * kempld_get_mutex must be called prior to calling this function.
191 */
192void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
193{
194 iowrite8(index, pld->io_index);
195 iowrite8(data, pld->io_data);
196}
197EXPORT_SYMBOL_GPL(kempld_write8);
198
199/**
200 * kempld_read16 - read 16 bit register
201 * @pld: kempld_device_data structure describing the PLD
202 * @index: register index on the chip
203 *
204 * kempld_get_mutex must be called prior to calling this function.
205 */
206u16 kempld_read16(struct kempld_device_data *pld, u8 index)
207{
208 return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
209}
210EXPORT_SYMBOL_GPL(kempld_read16);
211
212/**
213 * kempld_write16 - write 16 bit register
214 * @pld: kempld_device_data structure describing the PLD
215 * @index: register index on the chip
216 * @data: new register value
217 *
218 * kempld_get_mutex must be called prior to calling this function.
219 */
220void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
221{
222 kempld_write8(pld, index, (u8)data);
223 kempld_write8(pld, index + 1, (u8)(data >> 8));
224}
225EXPORT_SYMBOL_GPL(kempld_write16);
226
227/**
228 * kempld_read32 - read 32 bit register
229 * @pld: kempld_device_data structure describing the PLD
230 * @index: register index on the chip
231 *
232 * kempld_get_mutex must be called prior to calling this function.
233 */
234u32 kempld_read32(struct kempld_device_data *pld, u8 index)
235{
236 return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
237}
238EXPORT_SYMBOL_GPL(kempld_read32);
239
240/**
241 * kempld_write32 - write 32 bit register
242 * @pld: kempld_device_data structure describing the PLD
243 * @index: register index on the chip
244 * @data: new register value
245 *
246 * kempld_get_mutex must be called prior to calling this function.
247 */
248void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
249{
250 kempld_write16(pld, index, (u16)data);
251 kempld_write16(pld, index + 2, (u16)(data >> 16));
252}
253EXPORT_SYMBOL_GPL(kempld_write32);
254
255/**
256 * kempld_get_mutex - acquire PLD mutex
257 * @pld: kempld_device_data structure describing the PLD
258 */
259void kempld_get_mutex(struct kempld_device_data *pld)
260{
261 struct kempld_platform_data *pdata = pld->dev->platform_data;
262
263 mutex_lock(&pld->lock);
264 pdata->get_hardware_mutex(pld);
265}
266EXPORT_SYMBOL_GPL(kempld_get_mutex);
267
268/**
269 * kempld_release_mutex - release PLD mutex
270 * @pld: kempld_device_data structure describing the PLD
271 */
272void kempld_release_mutex(struct kempld_device_data *pld)
273{
274 struct kempld_platform_data *pdata = pld->dev->platform_data;
275
276 pdata->release_hardware_mutex(pld);
277 mutex_unlock(&pld->lock);
278}
279EXPORT_SYMBOL_GPL(kempld_release_mutex);
280
281/**
282 * kempld_get_info - update device specific information
283 * @pld: kempld_device_data structure describing the PLD
284 *
285 * This function calls the configured board specific kempld_get_info_XXXX
286 * function which is responsible for gathering information about the specific
287 * hardware. The information is then stored within the pld structure.
288 */
289static int kempld_get_info(struct kempld_device_data *pld)
290{
291 struct kempld_platform_data *pdata = pld->dev->platform_data;
292
293 return pdata->get_info(pld);
294}
295
296/*
297 * kempld_register_cells - register cell drivers
298 *
299 * This function registers cell drivers for the detected hardware by calling
300 * the configured kempld_register_cells_XXXX function which is responsible
301 * to detect and register the needed cell drivers.
302 */
303static int kempld_register_cells(struct kempld_device_data *pld)
304{
305 struct kempld_platform_data *pdata = pld->dev->platform_data;
306
307 return pdata->register_cells(pld);
308}
309
310static int kempld_detect_device(struct kempld_device_data *pld)
311{
312 char *version_type;
313 u8 index_reg;
314 int ret;
315
316 mutex_lock(&pld->lock);
317
318 /* Check for empty IO space */
319 index_reg = ioread8(pld->io_index);
320 if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
321 mutex_unlock(&pld->lock);
322 return -ENODEV;
323 }
324
325 /* Release hardware mutex if aquired */
326 if (!(index_reg & KEMPLD_MUTEX_KEY))
327 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
328
329 mutex_unlock(&pld->lock);
330
331 ret = kempld_get_info(pld);
332 if (ret)
333 return ret;
334
335 switch (pld->info.type) {
336 case 0:
337 version_type = "release";
338 break;
339 case 1:
340 version_type = "debug";
341 break;
342 case 2:
343 version_type = "custom";
344 break;
345 default:
346 version_type = "unspecified";
347 }
348
349 dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number);
350 dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n",
351 version_type, pld->info.major, pld->info.minor,
352 pld->info.buildnr, pld->info.spec_major,
353 pld->info.spec_minor);
354
355 return kempld_register_cells(pld);
356}
357
358static int kempld_probe(struct platform_device *pdev)
359{
360 struct kempld_platform_data *pdata = pdev->dev.platform_data;
361 struct device *dev = &pdev->dev;
362 struct kempld_device_data *pld;
363 struct resource *ioport;
364 int ret;
365
366 pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
367 if (!pld)
368 return -ENOMEM;
369
370 ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
371 if (!ioport)
372 return -EINVAL;
373
374 pld->io_base = devm_ioport_map(dev, ioport->start,
375 ioport->end - ioport->start);
376 if (!pld->io_base)
377 return -ENOMEM;
378
379 pld->io_index = pld->io_base;
380 pld->io_data = pld->io_base + 1;
381 pld->pld_clock = pdata->pld_clock;
382 pld->dev = dev;
383
384 mutex_init(&pld->lock);
385 platform_set_drvdata(pdev, pld);
386
387 ret = kempld_detect_device(pld);
388 if (ret)
389 return ret;
390
391 return 0;
392}
393
394static int kempld_remove(struct platform_device *pdev)
395{
396 struct kempld_device_data *pld = platform_get_drvdata(pdev);
397 struct kempld_platform_data *pdata = pld->dev->platform_data;
398
399 mfd_remove_devices(&pdev->dev);
400 pdata->release_hardware_mutex(pld);
401
402 return 0;
403}
404
405static struct platform_driver kempld_driver = {
406 .driver = {
407 .name = "kempld",
408 .owner = THIS_MODULE,
409 },
410 .probe = kempld_probe,
411 .remove = kempld_remove,
412};
413
414static struct dmi_system_id __initdata kempld_dmi_table[] = {
415 {
416 .ident = "CCR2",
417 .matches = {
418 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
419 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
420 },
421 .driver_data = (void *)&kempld_platform_data_generic,
422 .callback = kempld_create_platform_device,
423 }, {
424 .ident = "CCR6",
425 .matches = {
426 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
427 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
428 },
429 .driver_data = (void *)&kempld_platform_data_generic,
430 .callback = kempld_create_platform_device,
431 }, {
432 .ident = "CHR2",
433 .matches = {
434 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
435 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
436 },
437 .driver_data = (void *)&kempld_platform_data_generic,
438 .callback = kempld_create_platform_device,
439 }, {
440 .ident = "CHR2",
441 .matches = {
442 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
443 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
444 },
445 .driver_data = (void *)&kempld_platform_data_generic,
446 .callback = kempld_create_platform_device,
447 }, {
448 .ident = "CHR2",
449 .matches = {
450 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
451 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
452 },
453 .driver_data = (void *)&kempld_platform_data_generic,
454 .callback = kempld_create_platform_device,
455 }, {
456 .ident = "CHR6",
457 .matches = {
458 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
459 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
460 },
461 .driver_data = (void *)&kempld_platform_data_generic,
462 .callback = kempld_create_platform_device,
463 }, {
464 .ident = "CHR6",
465 .matches = {
466 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
467 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
468 },
469 .driver_data = (void *)&kempld_platform_data_generic,
470 .callback = kempld_create_platform_device,
471 }, {
472 .ident = "CHR6",
473 .matches = {
474 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
475 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
476 },
477 .driver_data = (void *)&kempld_platform_data_generic,
478 .callback = kempld_create_platform_device,
479 }, {
480 .ident = "CNTG",
481 .matches = {
482 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
483 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
484 },
485 .driver_data = (void *)&kempld_platform_data_generic,
486 .callback = kempld_create_platform_device,
487 }, {
488 .ident = "CNTG",
489 .matches = {
490 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
491 DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
492 },
493 .driver_data = (void *)&kempld_platform_data_generic,
494 .callback = kempld_create_platform_device,
495 }, {
496 .ident = "CNTX",
497 .matches = {
498 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
499 DMI_MATCH(DMI_BOARD_NAME, "PXT"),
500 },
501 .driver_data = (void *)&kempld_platform_data_generic,
502 .callback = kempld_create_platform_device,
503 }, {
504 .ident = "FRI2",
505 .matches = {
506 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
507 DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
508 },
509 .driver_data = (void *)&kempld_platform_data_generic,
510 .callback = kempld_create_platform_device,
511 }, {
512 .ident = "FRI2",
513 .matches = {
514 DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
515 },
516 .driver_data = (void *)&kempld_platform_data_generic,
517 .callback = kempld_create_platform_device,
518 }, {
519 .ident = "MBR1",
520 .matches = {
521 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
522 DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
523 },
524 .driver_data = (void *)&kempld_platform_data_generic,
525 .callback = kempld_create_platform_device,
526 }, {
527 .ident = "NTC1",
528 .matches = {
529 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
530 DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
531 },
532 .driver_data = (void *)&kempld_platform_data_generic,
533 .callback = kempld_create_platform_device,
534 }, {
535 .ident = "NTC1",
536 .matches = {
537 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
538 DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
539 },
540 .driver_data = (void *)&kempld_platform_data_generic,
541 .callback = kempld_create_platform_device,
542 }, {
543 .ident = "NTC1",
544 .matches = {
545 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
546 DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
547 },
548 .driver_data = (void *)&kempld_platform_data_generic,
549 .callback = kempld_create_platform_device,
550 }, {
551 .ident = "NUP1",
552 .matches = {
553 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
554 DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
555 },
556 .driver_data = (void *)&kempld_platform_data_generic,
557 .callback = kempld_create_platform_device,
558 }, {
559 .ident = "UNP1",
560 .matches = {
561 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
562 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
563 },
564 .driver_data = (void *)&kempld_platform_data_generic,
565 .callback = kempld_create_platform_device,
566 }, {
567 .ident = "UNP1",
568 .matches = {
569 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
570 DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
571 },
572 .driver_data = (void *)&kempld_platform_data_generic,
573 .callback = kempld_create_platform_device,
574 }, {
575 .ident = "UNTG",
576 .matches = {
577 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
578 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
579 },
580 .driver_data = (void *)&kempld_platform_data_generic,
581 .callback = kempld_create_platform_device,
582 }, {
583 .ident = "UNTG",
584 .matches = {
585 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
586 DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
587 },
588 .driver_data = (void *)&kempld_platform_data_generic,
589 .callback = kempld_create_platform_device,
590 }, {
591 .ident = "UUP6",
592 .matches = {
593 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
594 DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
595 },
596 .driver_data = (void *)&kempld_platform_data_generic,
597 .callback = kempld_create_platform_device,
598 },
599 {}
600};
601MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
602
603static int __init kempld_init(void)
604{
605 const struct dmi_system_id *id;
606 int ret;
607
608 if (force_device_id[0]) {
609 for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++)
610 if (strstr(id->ident, force_device_id))
611 if (id->callback && id->callback(id))
612 break;
613 if (id->matches[0].slot == DMI_NONE)
614 return -ENODEV;
615 } else {
616 if (!dmi_check_system(kempld_dmi_table))
617 return -ENODEV;
618 }
619
620 ret = platform_driver_register(&kempld_driver);
621 if (ret)
622 return ret;
623
624 return 0;
625}
626
627static void __exit kempld_exit(void)
628{
629 if (kempld_pdev)
630 platform_device_unregister(kempld_pdev);
631
632 platform_driver_unregister(&kempld_driver);
633}
634
635module_init(kempld_init);
636module_exit(kempld_exit);
637
638MODULE_DESCRIPTION("KEM PLD Core Driver");
639MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
640MODULE_LICENSE("GPL");
641MODULE_ALIAS("platform:kempld-core");
diff --git a/include/linux/mfd/kempld.h b/include/linux/mfd/kempld.h
new file mode 100644
index 000000000000..b911ef3add03
--- /dev/null
+++ b/include/linux/mfd/kempld.h
@@ -0,0 +1,125 @@
1/*
2 * Kontron PLD driver definitions
3 *
4 * Copyright (c) 2010-2012 Kontron Europe GmbH
5 * Author: Michael Brunner <michael.brunner@kontron.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License 2 as published
9 * by the Free Software Foundation.
10 */
11
12#ifndef _LINUX_MFD_KEMPLD_H_
13#define _LINUX_MFD_KEMPLD_H_
14
15/* kempld register definitions */
16#define KEMPLD_IOINDEX 0xa80
17#define KEMPLD_IODATA 0xa81
18#define KEMPLD_MUTEX_KEY 0x80
19#define KEMPLD_VERSION 0x00
20#define KEMPLD_VERSION_LSB 0x00
21#define KEMPLD_VERSION_MSB 0x01
22#define KEMPLD_VERSION_GET_MINOR(x) (x & 0x1f)
23#define KEMPLD_VERSION_GET_MAJOR(x) ((x >> 5) & 0x1f)
24#define KEMPLD_VERSION_GET_NUMBER(x) ((x >> 10) & 0xf)
25#define KEMPLD_VERSION_GET_TYPE(x) ((x >> 14) & 0x3)
26#define KEMPLD_BUILDNR 0x02
27#define KEMPLD_BUILDNR_LSB 0x02
28#define KEMPLD_BUILDNR_MSB 0x03
29#define KEMPLD_FEATURE 0x04
30#define KEMPLD_FEATURE_LSB 0x04
31#define KEMPLD_FEATURE_MSB 0x05
32#define KEMPLD_FEATURE_BIT_I2C (1 << 0)
33#define KEMPLD_FEATURE_BIT_WATCHDOG (1 << 1)
34#define KEMPLD_FEATURE_BIT_GPIO (1 << 2)
35#define KEMPLD_FEATURE_MASK_UART (7 << 3)
36#define KEMPLD_FEATURE_BIT_NMI (1 << 8)
37#define KEMPLD_FEATURE_BIT_SMI (1 << 9)
38#define KEMPLD_FEATURE_BIT_SCI (1 << 10)
39#define KEMPLD_SPEC 0x06
40#define KEMPLD_SPEC_GET_MINOR(x) (x & 0x0f)
41#define KEMPLD_SPEC_GET_MAJOR(x) ((x >> 4) & 0x0f)
42#define KEMPLD_IRQ_GPIO 0x35
43#define KEMPLD_IRQ_I2C 0x36
44#define KEMPLD_CFG 0x37
45#define KEMPLD_CFG_GPIO_I2C_MUX (1 << 0)
46#define KEMPLD_CFG_BIOS_WP (1 << 7)
47
48#define KEMPLD_CLK 33333333
49
50#define KEMPLD_TYPE_RELEASE 0x0
51#define KEMPLD_TYPE_DEBUG 0x1
52#define KEMPLD_TYPE_CUSTOM 0x2
53
54/**
55 * struct kempld_info - PLD device information structure
56 * @major: PLD major revision
57 * @minor: PLD minor revision
58 * @buildnr: PLD build number
59 * @number: PLD board specific index
60 * @type: PLD type
61 * @spec_major: PLD FW specification major revision
62 * @spec_minor: PLD FW specification minor revision
63 */
64struct kempld_info {
65 unsigned int major;
66 unsigned int minor;
67 unsigned int buildnr;
68 unsigned int number;
69 unsigned int type;
70 unsigned int spec_major;
71 unsigned int spec_minor;
72};
73
74/**
75 * struct kempld_device_data - Internal representation of the PLD device
76 * @io_base: Pointer to the IO memory
77 * @io_index: Pointer to the IO index register
78 * @io_data: Pointer to the IO data register
79 * @pld_clock: PLD clock frequency
80 * @feature_mask: PLD feature mask
81 * @dev: Pointer to kernel device structure
82 * @info: KEMPLD info structure
83 * @lock: PLD mutex
84 */
85struct kempld_device_data {
86 void __iomem *io_base;
87 void __iomem *io_index;
88 void __iomem *io_data;
89 u32 pld_clock;
90 u32 feature_mask;
91 struct device *dev;
92 struct kempld_info info;
93 struct mutex lock;
94};
95
96/**
97 * struct kempld_platform_data - PLD hardware configuration structure
98 * @pld_clock: PLD clock frequency
99 * @gpio_base GPIO base pin number
100 * @ioresource: IO addresses of the PLD
101 * @get_mutex: PLD specific get_mutex callback
102 * @release_mutex: PLD specific release_mutex callback
103 * @get_info: PLD specific get_info callback
104 * @register_cells: PLD specific register_cells callback
105 */
106struct kempld_platform_data {
107 u32 pld_clock;
108 int gpio_base;
109 struct resource *ioresource;
110 void (*get_hardware_mutex) (struct kempld_device_data *);
111 void (*release_hardware_mutex) (struct kempld_device_data *);
112 int (*get_info) (struct kempld_device_data *);
113 int (*register_cells) (struct kempld_device_data *);
114};
115
116extern void kempld_get_mutex(struct kempld_device_data *pld);
117extern void kempld_release_mutex(struct kempld_device_data *pld);
118extern u8 kempld_read8(struct kempld_device_data *pld, u8 index);
119extern void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data);
120extern u16 kempld_read16(struct kempld_device_data *pld, u8 index);
121extern void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data);
122extern u32 kempld_read32(struct kempld_device_data *pld, u8 index);
123extern void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data);
124
125#endif /* _LINUX_MFD_KEMPLD_H_ */