linux/drivers/mcb/mcb-lpc.c
<<
>>
Prefs
   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
  19struct priv {
  20        struct mcb_bus *bus;
  21        struct resource *mem;
  22        void __iomem *base;
  23};
  24
  25static 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
  76static 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
  85static struct platform_device *mcb_lpc_pdev;
  86
  87static 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
 106out_put:
 107        platform_device_put(mcb_lpc_pdev);
 108        return ret;
 109}
 110
 111static struct resource sc24_fpga_resource = {
 112        .start = 0xe000e000,
 113        .end = 0xe000e000 + CHAM_HEADER_SIZE,
 114        .flags = IORESOURCE_MEM,
 115};
 116
 117static 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
 125static 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};
 137MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table);
 138
 139static 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
 147static void __exit mcb_lpc_exit(void)
 148{
 149        platform_device_unregister(mcb_lpc_pdev);
 150        platform_driver_unregister(&mcb_lpc_driver);
 151}
 152
 153module_init(mcb_lpc_init);
 154module_exit(mcb_lpc_exit);
 155
 156MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
 157MODULE_LICENSE("GPL");
 158MODULE_DESCRIPTION("MCB over LPC support");
 159