0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/platform_device.h>
0010 #include <linux/module.h>
0011 #include <linux/dmi.h>
0012 #include <linux/mcb.h>
0013 #include <linux/io.h>
0014 #include "mcb-internal.h"
0015
0016 struct priv {
0017 struct mcb_bus *bus;
0018 struct resource *mem;
0019 void __iomem *base;
0020 };
0021
0022 static int mcb_lpc_probe(struct platform_device *pdev)
0023 {
0024 struct resource *res;
0025 struct priv *priv;
0026 int ret = 0;
0027
0028 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0029 if (!priv)
0030 return -ENOMEM;
0031
0032 priv->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0033 if (!priv->mem) {
0034 dev_err(&pdev->dev, "No Memory resource\n");
0035 return -ENODEV;
0036 }
0037
0038 res = devm_request_mem_region(&pdev->dev, priv->mem->start,
0039 resource_size(priv->mem),
0040 KBUILD_MODNAME);
0041 if (!res) {
0042 dev_err(&pdev->dev, "Failed to request IO memory\n");
0043 return -EBUSY;
0044 }
0045
0046 priv->base = devm_ioremap(&pdev->dev, priv->mem->start,
0047 resource_size(priv->mem));
0048 if (!priv->base) {
0049 dev_err(&pdev->dev, "Cannot ioremap\n");
0050 return -ENOMEM;
0051 }
0052
0053 platform_set_drvdata(pdev, priv);
0054
0055 priv->bus = mcb_alloc_bus(&pdev->dev);
0056 if (IS_ERR(priv->bus))
0057 return PTR_ERR(priv->bus);
0058
0059 ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base);
0060 if (ret < 0) {
0061 mcb_release_bus(priv->bus);
0062 return ret;
0063 }
0064
0065 dev_dbg(&pdev->dev, "Found %d cells\n", ret);
0066
0067 mcb_bus_add_devices(priv->bus);
0068
0069 return 0;
0070
0071 }
0072
0073 static int mcb_lpc_remove(struct platform_device *pdev)
0074 {
0075 struct priv *priv = platform_get_drvdata(pdev);
0076
0077 mcb_release_bus(priv->bus);
0078
0079 return 0;
0080 }
0081
0082 static struct platform_device *mcb_lpc_pdev;
0083
0084 static int mcb_lpc_create_platform_device(const struct dmi_system_id *id)
0085 {
0086 struct resource *res = id->driver_data;
0087 int ret;
0088
0089 mcb_lpc_pdev = platform_device_alloc("mcb-lpc", -1);
0090 if (!mcb_lpc_pdev)
0091 return -ENOMEM;
0092
0093 ret = platform_device_add_resources(mcb_lpc_pdev, res, 1);
0094 if (ret)
0095 goto out_put;
0096
0097 ret = platform_device_add(mcb_lpc_pdev);
0098 if (ret)
0099 goto out_put;
0100
0101 return 0;
0102
0103 out_put:
0104 platform_device_put(mcb_lpc_pdev);
0105 return ret;
0106 }
0107
0108 static struct resource sc24_fpga_resource = DEFINE_RES_MEM(0xe000e000, CHAM_HEADER_SIZE);
0109 static struct resource sc31_fpga_resource = DEFINE_RES_MEM(0xf000e000, CHAM_HEADER_SIZE);
0110
0111 static struct platform_driver mcb_lpc_driver = {
0112 .driver = {
0113 .name = "mcb-lpc",
0114 },
0115 .probe = mcb_lpc_probe,
0116 .remove = mcb_lpc_remove,
0117 };
0118
0119 static const struct dmi_system_id mcb_lpc_dmi_table[] = {
0120 {
0121 .ident = "SC24",
0122 .matches = {
0123 DMI_MATCH(DMI_SYS_VENDOR, "MEN"),
0124 DMI_MATCH(DMI_PRODUCT_VERSION, "14SC24"),
0125 },
0126 .driver_data = (void *)&sc24_fpga_resource,
0127 .callback = mcb_lpc_create_platform_device,
0128 },
0129 {
0130 .ident = "SC31",
0131 .matches = {
0132 DMI_MATCH(DMI_SYS_VENDOR, "MEN"),
0133 DMI_MATCH(DMI_PRODUCT_VERSION, "14SC31"),
0134 },
0135 .driver_data = (void *)&sc31_fpga_resource,
0136 .callback = mcb_lpc_create_platform_device,
0137 },
0138 {}
0139 };
0140 MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table);
0141
0142 static int __init mcb_lpc_init(void)
0143 {
0144 if (!dmi_check_system(mcb_lpc_dmi_table))
0145 return -ENODEV;
0146
0147 return platform_driver_register(&mcb_lpc_driver);
0148 }
0149
0150 static void __exit mcb_lpc_exit(void)
0151 {
0152 platform_device_unregister(mcb_lpc_pdev);
0153 platform_driver_unregister(&mcb_lpc_driver);
0154 }
0155
0156 module_init(mcb_lpc_init);
0157 module_exit(mcb_lpc_exit);
0158
0159 MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
0160 MODULE_LICENSE("GPL");
0161 MODULE_DESCRIPTION("MCB over LPC support");
0162 MODULE_IMPORT_NS(MCB);