diff options
-rw-r--r-- | drivers/mcb/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mcb/Makefile | 1 | ||||
-rw-r--r-- | drivers/mcb/mcb-lpc.c | 158 |
3 files changed, 168 insertions, 0 deletions
diff --git a/drivers/mcb/Kconfig b/drivers/mcb/Kconfig index e9a6976e1010..76d9c51de6c9 100644 --- a/drivers/mcb/Kconfig +++ b/drivers/mcb/Kconfig | |||
@@ -28,4 +28,13 @@ config MCB_PCI | |||
28 | 28 | ||
29 | If build as a module, the module is called mcb-pci.ko | 29 | If build as a module, the module is called mcb-pci.ko |
30 | 30 | ||
31 | config MCB_LPC | ||
32 | tristate "LPC (non PCI) based MCB carrier" | ||
33 | default n | ||
34 | help | ||
35 | |||
36 | This is a MCB carrier on a LPC or non PCI device. | ||
37 | |||
38 | If build as a module, the module is called mcb-lpc.ko | ||
39 | |||
31 | endif # MCB | 40 | endif # MCB |
diff --git a/drivers/mcb/Makefile b/drivers/mcb/Makefile index 1ae141311def..bcc7745774ab 100644 --- a/drivers/mcb/Makefile +++ b/drivers/mcb/Makefile | |||
@@ -5,3 +5,4 @@ mcb-y += mcb-core.o | |||
5 | mcb-y += mcb-parse.o | 5 | mcb-y += mcb-parse.o |
6 | 6 | ||
7 | obj-$(CONFIG_MCB_PCI) += mcb-pci.o | 7 | obj-$(CONFIG_MCB_PCI) += mcb-pci.o |
8 | obj-$(CONFIG_MCB_LPC) += mcb-lpc.o | ||
diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c new file mode 100644 index 000000000000..d072c088ce73 --- /dev/null +++ b/drivers/mcb/mcb-lpc.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * MEN Chameleon Bus. | ||
3 | * | ||
4 | * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) | ||
5 | * Author: Andreas Werner <andreas.werner@men.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the Free | ||
9 | * Software Foundation; version 2 of the License. | ||
10 | */ | ||
11 | |||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/dmi.h> | ||
15 | #include <linux/mcb.h> | ||
16 | #include <linux/io.h> | ||
17 | #include "mcb-internal.h" | ||
18 | |||
19 | struct priv { | ||
20 | struct mcb_bus *bus; | ||
21 | struct resource *mem; | ||
22 | void __iomem *base; | ||
23 | }; | ||
24 | |||
25 | static int mcb_lpc_probe(struct platform_device *pdev) | ||
26 | { | ||
27 | struct resource *res; | ||
28 | struct priv *priv; | ||
29 | int ret = 0; | ||
30 | |||
31 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
32 | if (!priv) | ||
33 | return -ENOMEM; | ||
34 | |||
35 | priv->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
36 | if (!priv->mem) { | ||
37 | dev_err(&pdev->dev, "No Memory resource\n"); | ||
38 | return -ENODEV; | ||
39 | } | ||
40 | |||
41 | res = devm_request_mem_region(&pdev->dev, priv->mem->start, | ||
42 | resource_size(priv->mem), | ||
43 | KBUILD_MODNAME); | ||
44 | if (!res) { | ||
45 | dev_err(&pdev->dev, "Failed to request IO memory\n"); | ||
46 | return -EBUSY; | ||
47 | } | ||
48 | |||
49 | priv->base = devm_ioremap(&pdev->dev, priv->mem->start, | ||
50 | resource_size(priv->mem)); | ||
51 | if (!priv->base) { | ||
52 | dev_err(&pdev->dev, "Cannot ioremap\n"); | ||
53 | return -ENOMEM; | ||
54 | } | ||
55 | |||
56 | platform_set_drvdata(pdev, priv); | ||
57 | |||
58 | priv->bus = mcb_alloc_bus(&pdev->dev); | ||
59 | if (IS_ERR(priv->bus)) | ||
60 | return PTR_ERR(priv->bus); | ||
61 | |||
62 | ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base); | ||
63 | if (ret < 0) { | ||
64 | mcb_release_bus(priv->bus); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | dev_dbg(&pdev->dev, "Found %d cells\n", ret); | ||
69 | |||
70 | mcb_bus_add_devices(priv->bus); | ||
71 | |||
72 | return 0; | ||
73 | |||
74 | } | ||
75 | |||
76 | static int mcb_lpc_remove(struct platform_device *pdev) | ||
77 | { | ||
78 | struct priv *priv = platform_get_drvdata(pdev); | ||
79 | |||
80 | mcb_release_bus(priv->bus); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct platform_device *mcb_lpc_pdev; | ||
86 | |||
87 | static int mcb_lpc_create_platform_device(const struct dmi_system_id *id) | ||
88 | { | ||
89 | struct resource *res = id->driver_data; | ||
90 | int ret; | ||
91 | |||
92 | mcb_lpc_pdev = platform_device_alloc("mcb-lpc", -1); | ||
93 | if (!mcb_lpc_pdev) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | ret = platform_device_add_resources(mcb_lpc_pdev, res, 1); | ||
97 | if (ret) | ||
98 | goto out_put; | ||
99 | |||
100 | ret = platform_device_add(mcb_lpc_pdev); | ||
101 | if (ret) | ||
102 | goto out_put; | ||
103 | |||
104 | return 0; | ||
105 | |||
106 | out_put: | ||
107 | platform_device_put(mcb_lpc_pdev); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static struct resource sc24_fpga_resource = { | ||
112 | .start = 0xe000e000, | ||
113 | .end = 0xe000e000 + CHAM_HEADER_SIZE, | ||
114 | .flags = IORESOURCE_MEM, | ||
115 | }; | ||
116 | |||
117 | static struct platform_driver mcb_lpc_driver = { | ||
118 | .driver = { | ||
119 | .name = "mcb-lpc", | ||
120 | }, | ||
121 | .probe = mcb_lpc_probe, | ||
122 | .remove = mcb_lpc_remove, | ||
123 | }; | ||
124 | |||
125 | static const struct dmi_system_id mcb_lpc_dmi_table[] = { | ||
126 | { | ||
127 | .ident = "SC24", | ||
128 | .matches = { | ||
129 | DMI_MATCH(DMI_SYS_VENDOR, "MEN"), | ||
130 | DMI_MATCH(DMI_PRODUCT_VERSION, "14SC24"), | ||
131 | }, | ||
132 | .driver_data = (void *)&sc24_fpga_resource, | ||
133 | .callback = mcb_lpc_create_platform_device, | ||
134 | }, | ||
135 | {} | ||
136 | }; | ||
137 | MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table); | ||
138 | |||
139 | static int __init mcb_lpc_init(void) | ||
140 | { | ||
141 | if (!dmi_check_system(mcb_lpc_dmi_table)) | ||
142 | return -ENODEV; | ||
143 | |||
144 | return platform_driver_register(&mcb_lpc_driver); | ||
145 | } | ||
146 | |||
147 | static void __exit mcb_lpc_exit(void) | ||
148 | { | ||
149 | platform_device_unregister(mcb_lpc_pdev); | ||
150 | platform_driver_unregister(&mcb_lpc_driver); | ||
151 | } | ||
152 | |||
153 | module_init(mcb_lpc_init); | ||
154 | module_exit(mcb_lpc_exit); | ||
155 | |||
156 | MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); | ||
157 | MODULE_LICENSE("GPL"); | ||
158 | MODULE_DESCRIPTION("MCB over LPC support"); | ||