1e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima/* 2e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * Copyright (C) 2007 Google, Inc. 3e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * Copyright (C) 2011 Intel, Inc. 4e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * Copyright (C) 2013 Intel, Inc. 5e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * 6e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * This software is licensed under the terms of the GNU General Public 7e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * License version 2, as published by the Free Software Foundation, and 8e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * may be copied, distributed, and modified under those terms. 9e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * 10e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * This program is distributed in the hope that it will be useful, 11e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * GNU General Public License for more details. 14e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima * 15e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima */ 16e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 17e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/kernel.h> 18e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/init.h> 19e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/interrupt.h> 20e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/irq.h> 21e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/platform_device.h> 22e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/slab.h> 23e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#include <linux/io.h> 24e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 25e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_OP_DONE (0x00) 26e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_OP_REMOVE_DEV (0x04) 27e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_OP_ADD_DEV (0x08) 28e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 29e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_OP_INIT (0x00) 30e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 31e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_OP (0x00) 32e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_GET_NAME (0x04) 33e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_NAME_LEN (0x08) 34e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_ID (0x0c) 35e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_IO_BASE (0x10) 36e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_IO_SIZE (0x14) 37e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_IRQ (0x18) 38e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima#define PDEV_BUS_IRQ_COUNT (0x1c) 39f10d8434201859d5ad7f51032dcd2d0c09e85ee2Octavian Purdila#define PDEV_BUS_GET_NAME_HIGH (0x20) 40e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 41e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastruct pdev_bus_dev { 42e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct list_head list; 43e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct platform_device pdev; 44e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct resource resources[0]; 45e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima}; 46e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 47e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic void goldfish_pdev_worker(struct work_struct *work); 48e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 49e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic void __iomem *pdev_bus_base; 50e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic unsigned long pdev_bus_addr; 51e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic unsigned long pdev_bus_len; 52e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic u32 pdev_bus_irq; 53e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic LIST_HEAD(pdev_bus_new_devices); 54e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic LIST_HEAD(pdev_bus_registered_devices); 55e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic LIST_HEAD(pdev_bus_removed_devices); 56e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic DECLARE_WORK(pdev_bus_worker, goldfish_pdev_worker); 57e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 58e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 59e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic void goldfish_pdev_worker(struct work_struct *work) 60e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima{ 61e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima int ret; 62e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct pdev_bus_dev *pos, *n; 63e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 64e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_for_each_entry_safe(pos, n, &pdev_bus_removed_devices, list) { 65e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_del(&pos->list); 66e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima platform_device_unregister(&pos->pdev); 67e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima kfree(pos); 68e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 69e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_for_each_entry_safe(pos, n, &pdev_bus_new_devices, list) { 70e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_del(&pos->list); 71e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima ret = platform_device_register(&pos->pdev); 72e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (ret) 73e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pr_err("goldfish_pdev_worker failed to register device, %s\n", 74e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pos->pdev.name); 75e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_add_tail(&pos->list, &pdev_bus_registered_devices); 76e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 77e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima} 78e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 79e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic void goldfish_pdev_remove(void) 80e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima{ 81e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct pdev_bus_dev *pos, *n; 82e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima u32 base; 83e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 84e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima base = readl(pdev_bus_base + PDEV_BUS_IO_BASE); 85e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 86e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_for_each_entry_safe(pos, n, &pdev_bus_new_devices, list) { 87e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (pos->resources[0].start == base) { 88e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_del(&pos->list); 89e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima kfree(pos); 90e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return; 91e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 92e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 93e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_for_each_entry_safe(pos, n, &pdev_bus_registered_devices, list) { 94e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (pos->resources[0].start == base) { 95e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_del(&pos->list); 96e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_add_tail(&pos->list, &pdev_bus_removed_devices); 97e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima schedule_work(&pdev_bus_worker); 98e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return; 99e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 100e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima }; 101e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pr_err("goldfish_pdev_remove could not find device at %x\n", base); 102e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima} 103e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 104e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic int goldfish_new_pdev(void) 105e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima{ 106e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct pdev_bus_dev *dev; 107e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima u32 name_len; 108e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima u32 irq = -1, irq_count; 109e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima int resource_count = 2; 110e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima u32 base; 111e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima char *name; 112e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 113e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima base = readl(pdev_bus_base + PDEV_BUS_IO_BASE); 114e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 115e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima irq_count = readl(pdev_bus_base + PDEV_BUS_IRQ_COUNT); 116e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima name_len = readl(pdev_bus_base + PDEV_BUS_NAME_LEN); 117e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (irq_count) 118e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima resource_count++; 119e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 120e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev = kzalloc(sizeof(*dev) + 121e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima sizeof(struct resource) * resource_count + 122e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima name_len + 1 + sizeof(*dev->pdev.dev.dma_mask), GFP_ATOMIC); 123e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (dev == NULL) 124e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return -ENOMEM; 125e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 126e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.num_resources = resource_count; 127e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource = (struct resource *)(dev + 1); 128e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.name = name = (char *)(dev->pdev.resource + resource_count); 129e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.dev.coherent_dma_mask = ~0; 130e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.dev.dma_mask = (void *)(dev->pdev.name + name_len + 1); 131e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima *dev->pdev.dev.dma_mask = ~0; 132e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 133f10d8434201859d5ad7f51032dcd2d0c09e85ee2Octavian Purdila#ifdef CONFIG_64BIT 134f10d8434201859d5ad7f51032dcd2d0c09e85ee2Octavian Purdila writel((u32)((u64)name>>32), pdev_bus_base + PDEV_BUS_GET_NAME_HIGH); 135f10d8434201859d5ad7f51032dcd2d0c09e85ee2Octavian Purdila#endif 136f2dbdf625ddc98fece71a79d78d0981204e933eeOctavian Purdila writel((u32)(unsigned long)name, pdev_bus_base + PDEV_BUS_GET_NAME); 137e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima name[name_len] = '\0'; 138e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.id = readl(pdev_bus_base + PDEV_BUS_ID); 139e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource[0].start = base; 140e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource[0].end = base + 141e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima readl(pdev_bus_base + PDEV_BUS_IO_SIZE) - 1; 142e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource[0].flags = IORESOURCE_MEM; 143e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (irq_count) { 144e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima irq = readl(pdev_bus_base + PDEV_BUS_IRQ); 145e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource[1].start = irq; 146e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource[1].end = irq + irq_count - 1; 147e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev->pdev.resource[1].flags = IORESOURCE_IRQ; 148e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 149e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 150e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pr_debug("goldfish_new_pdev %s at %x irq %d\n", name, base, irq); 151e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima list_add_tail(&dev->list, &pdev_bus_new_devices); 152e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima schedule_work(&pdev_bus_worker); 153e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 154e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return 0; 155e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima} 156e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 157e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic irqreturn_t goldfish_pdev_bus_interrupt(int irq, void *dev_id) 158e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima{ 159e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima irqreturn_t ret = IRQ_NONE; 160e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima while (1) { 161e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima u32 op = readl(pdev_bus_base + PDEV_BUS_OP); 162e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima switch (op) { 163e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima case PDEV_BUS_OP_DONE: 164e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return IRQ_NONE; 165e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 166e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima case PDEV_BUS_OP_REMOVE_DEV: 167e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima goldfish_pdev_remove(); 168e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima break; 169e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 170e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima case PDEV_BUS_OP_ADD_DEV: 171e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima goldfish_new_pdev(); 172e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima break; 173e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 174e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima ret = IRQ_HANDLED; 175e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 176e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return ret; 177e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima} 178e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 179e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic int goldfish_pdev_bus_probe(struct platform_device *pdev) 180e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima{ 181e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima int ret; 182e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima struct resource *r; 183e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 184e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 185e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (r == NULL) 186e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return -EINVAL; 187e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 188e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pdev_bus_addr = r->start; 189e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pdev_bus_len = resource_size(r); 190e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 191e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pdev_bus_base = ioremap(pdev_bus_addr, pdev_bus_len); 192e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (pdev_bus_base == NULL) { 193e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima ret = -ENOMEM; 194e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev_err(&pdev->dev, "unable to map Goldfish MMIO.\n"); 195e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima goto free_resources; 196e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 197e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 198e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 199e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (r == NULL) { 200e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima ret = -ENOENT; 201e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima goto free_map; 202e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 203e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 204e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima pdev_bus_irq = r->start; 205e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 206e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima ret = request_irq(pdev_bus_irq, goldfish_pdev_bus_interrupt, 207e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima IRQF_SHARED, "goldfish_pdev_bus", pdev); 208e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima if (ret) { 209e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima dev_err(&pdev->dev, "unable to request Goldfish IRQ\n"); 210e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima goto free_map; 211e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 212e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 213e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima writel(PDEV_BUS_OP_INIT, pdev_bus_base + PDEV_BUS_OP); 214e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return 0; 215e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 216e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimafree_map: 217e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima iounmap(pdev_bus_base); 218e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimafree_resources: 219e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima release_mem_region(pdev_bus_addr, pdev_bus_len); 220e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return ret; 221e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima} 222e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 223e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic int goldfish_pdev_bus_remove(struct platform_device *pdev) 224e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima{ 225e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima iounmap(pdev_bus_base); 226e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima free_irq(pdev_bus_irq, pdev); 227e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima release_mem_region(pdev_bus_addr, pdev_bus_len); 228e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima return 0; 229e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima} 230e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 231e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimastatic struct platform_driver goldfish_pdev_bus_driver = { 232e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima .probe = goldfish_pdev_bus_probe, 233e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima .remove = goldfish_pdev_bus_remove, 234e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima .driver = { 235e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima .name = "goldfish_pdev_bus" 236e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima } 237e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima}; 238e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajima 239e809c22b8fb0282048fc008cfcdd017186090dbcJun Nakajimamodule_platform_driver(goldfish_pdev_bus_driver); 240