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 resource sc31_fpga_resource = { 118 .start = 0xf000e000, 119 .end = 0xf000e000 + CHAM_HEADER_SIZE, 120 .flags = IORESOURCE_MEM, 121 }; 122 123 static struct platform_driver mcb_lpc_driver = { 124 .driver = { 125 .name = "mcb-lpc", 126 }, 127 .probe = mcb_lpc_probe, 128 .remove = mcb_lpc_remove, 129 }; 130 131 static const struct dmi_system_id mcb_lpc_dmi_table[] = { 132 { 133 .ident = "SC24", 134 .matches = { 135 DMI_MATCH(DMI_SYS_VENDOR, "MEN"), 136 DMI_MATCH(DMI_PRODUCT_VERSION, "14SC24"), 137 }, 138 .driver_data = (void *)&sc24_fpga_resource, 139 .callback = mcb_lpc_create_platform_device, 140 }, 141 { 142 .ident = "SC31", 143 .matches = { 144 DMI_MATCH(DMI_SYS_VENDOR, "MEN"), 145 DMI_MATCH(DMI_PRODUCT_VERSION, "14SC31"), 146 }, 147 .driver_data = (void *)&sc31_fpga_resource, 148 .callback = mcb_lpc_create_platform_device, 149 }, 150 {} 151 }; 152 MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table); 153 154 static int __init mcb_lpc_init(void) 155 { 156 if (!dmi_check_system(mcb_lpc_dmi_table)) 157 return -ENODEV; 158 159 return platform_driver_register(&mcb_lpc_driver); 160 } 161 162 static void __exit mcb_lpc_exit(void) 163 { 164 platform_device_unregister(mcb_lpc_pdev); 165 platform_driver_unregister(&mcb_lpc_driver); 166 } 167 168 module_init(mcb_lpc_init); 169 module_exit(mcb_lpc_exit); 170 171 MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); 172 MODULE_LICENSE("GPL"); 173 MODULE_DESCRIPTION("MCB over LPC support"); 174