Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * MEN Chameleon Bus.
0004  *
0005  * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
0006  * Author: Andreas Werner <andreas.werner@men.de>
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);