Path: blob/master/drivers/misc/spear13xx_pcie_gadget.c
15109 views
/*1* drivers/misc/spear13xx_pcie_gadget.c2*3* Copyright (C) 2010 ST Microelectronics4* Pratyush Anand<[email protected]>5*6* This file is licensed under the terms of the GNU General Public7* License version 2. This program is licensed "as is" without any8* warranty of any kind, whether express or implied.9*/1011#include <linux/clk.h>12#include <linux/slab.h>13#include <linux/delay.h>14#include <linux/io.h>15#include <linux/interrupt.h>16#include <linux/irq.h>17#include <linux/kernel.h>18#include <linux/module.h>19#include <linux/platform_device.h>20#include <linux/pci_regs.h>21#include <linux/configfs.h>22#include <mach/pcie.h>23#include <mach/misc_regs.h>2425#define IN0_MEM_SIZE (200 * 1024 * 1024 - 1)26/* In current implementation address translation is done using IN0 only.27* So IN1 start address and IN0 end address has been kept same28*/29#define IN1_MEM_SIZE (0 * 1024 * 1024 - 1)30#define IN_IO_SIZE (20 * 1024 * 1024 - 1)31#define IN_CFG0_SIZE (12 * 1024 * 1024 - 1)32#define IN_CFG1_SIZE (12 * 1024 * 1024 - 1)33#define IN_MSG_SIZE (12 * 1024 * 1024 - 1)34/* Keep default BAR size as 4K*/35/* AORAM would be mapped by default*/36#define INBOUND_ADDR_MASK (SPEAR13XX_SYSRAM1_SIZE - 1)3738#define INT_TYPE_NO_INT 039#define INT_TYPE_INTX 140#define INT_TYPE_MSI 241struct spear_pcie_gadget_config {42void __iomem *base;43void __iomem *va_app_base;44void __iomem *va_dbi_base;45char int_type[10];46ulong requested_msi;47ulong configured_msi;48ulong bar0_size;49ulong bar0_rw_offset;50void __iomem *va_bar0_address;51};5253struct pcie_gadget_target {54struct configfs_subsystem subsys;55struct spear_pcie_gadget_config config;56};5758struct pcie_gadget_target_attr {59struct configfs_attribute attr;60ssize_t (*show)(struct spear_pcie_gadget_config *config,61char *buf);62ssize_t (*store)(struct spear_pcie_gadget_config *config,63const char *buf,64size_t count);65};6667static void enable_dbi_access(struct pcie_app_reg __iomem *app_reg)68{69/* Enable DBI access */70writel(readl(&app_reg->slv_armisc) | (1 << AXI_OP_DBI_ACCESS_ID),71&app_reg->slv_armisc);72writel(readl(&app_reg->slv_awmisc) | (1 << AXI_OP_DBI_ACCESS_ID),73&app_reg->slv_awmisc);7475}7677static void disable_dbi_access(struct pcie_app_reg __iomem *app_reg)78{79/* disable DBI access */80writel(readl(&app_reg->slv_armisc) & ~(1 << AXI_OP_DBI_ACCESS_ID),81&app_reg->slv_armisc);82writel(readl(&app_reg->slv_awmisc) & ~(1 << AXI_OP_DBI_ACCESS_ID),83&app_reg->slv_awmisc);8485}8687static void spear_dbi_read_reg(struct spear_pcie_gadget_config *config,88int where, int size, u32 *val)89{90struct pcie_app_reg __iomem *app_reg = config->va_app_base;91ulong va_address;9293/* Enable DBI access */94enable_dbi_access(app_reg);9596va_address = (ulong)config->va_dbi_base + (where & ~0x3);9798*val = readl(va_address);99100if (size == 1)101*val = (*val >> (8 * (where & 3))) & 0xff;102else if (size == 2)103*val = (*val >> (8 * (where & 3))) & 0xffff;104105/* Disable DBI access */106disable_dbi_access(app_reg);107}108109static void spear_dbi_write_reg(struct spear_pcie_gadget_config *config,110int where, int size, u32 val)111{112struct pcie_app_reg __iomem *app_reg = config->va_app_base;113ulong va_address;114115/* Enable DBI access */116enable_dbi_access(app_reg);117118va_address = (ulong)config->va_dbi_base + (where & ~0x3);119120if (size == 4)121writel(val, va_address);122else if (size == 2)123writew(val, va_address + (where & 2));124else if (size == 1)125writeb(val, va_address + (where & 3));126127/* Disable DBI access */128disable_dbi_access(app_reg);129}130131#define PCI_FIND_CAP_TTL 48132133static int pci_find_own_next_cap_ttl(struct spear_pcie_gadget_config *config,134u32 pos, int cap, int *ttl)135{136u32 id;137138while ((*ttl)--) {139spear_dbi_read_reg(config, pos, 1, &pos);140if (pos < 0x40)141break;142pos &= ~3;143spear_dbi_read_reg(config, pos + PCI_CAP_LIST_ID, 1, &id);144if (id == 0xff)145break;146if (id == cap)147return pos;148pos += PCI_CAP_LIST_NEXT;149}150return 0;151}152153static int pci_find_own_next_cap(struct spear_pcie_gadget_config *config,154u32 pos, int cap)155{156int ttl = PCI_FIND_CAP_TTL;157158return pci_find_own_next_cap_ttl(config, pos, cap, &ttl);159}160161static int pci_find_own_cap_start(struct spear_pcie_gadget_config *config,162u8 hdr_type)163{164u32 status;165166spear_dbi_read_reg(config, PCI_STATUS, 2, &status);167if (!(status & PCI_STATUS_CAP_LIST))168return 0;169170switch (hdr_type) {171case PCI_HEADER_TYPE_NORMAL:172case PCI_HEADER_TYPE_BRIDGE:173return PCI_CAPABILITY_LIST;174case PCI_HEADER_TYPE_CARDBUS:175return PCI_CB_CAPABILITY_LIST;176default:177return 0;178}179180return 0;181}182183/*184* Tell if a device supports a given PCI capability.185* Returns the address of the requested capability structure within the186* device's PCI configuration space or 0 in case the device does not187* support it. Possible values for @cap:188*189* %PCI_CAP_ID_PM Power Management190* %PCI_CAP_ID_AGP Accelerated Graphics Port191* %PCI_CAP_ID_VPD Vital Product Data192* %PCI_CAP_ID_SLOTID Slot Identification193* %PCI_CAP_ID_MSI Message Signalled Interrupts194* %PCI_CAP_ID_CHSWP CompactPCI HotSwap195* %PCI_CAP_ID_PCIX PCI-X196* %PCI_CAP_ID_EXP PCI Express197*/198static int pci_find_own_capability(struct spear_pcie_gadget_config *config,199int cap)200{201u32 pos;202u32 hdr_type;203204spear_dbi_read_reg(config, PCI_HEADER_TYPE, 1, &hdr_type);205206pos = pci_find_own_cap_start(config, hdr_type);207if (pos)208pos = pci_find_own_next_cap(config, pos, cap);209210return pos;211}212213static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id)214{215return 0;216}217218/*219* configfs interfaces show/store functions220*/221static ssize_t pcie_gadget_show_link(222struct spear_pcie_gadget_config *config,223char *buf)224{225struct pcie_app_reg __iomem *app_reg = config->va_app_base;226227if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID))228return sprintf(buf, "UP");229else230return sprintf(buf, "DOWN");231}232233static ssize_t pcie_gadget_store_link(234struct spear_pcie_gadget_config *config,235const char *buf, size_t count)236{237struct pcie_app_reg __iomem *app_reg = config->va_app_base;238239if (sysfs_streq(buf, "UP"))240writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID),241&app_reg->app_ctrl_0);242else if (sysfs_streq(buf, "DOWN"))243writel(readl(&app_reg->app_ctrl_0)244& ~(1 << APP_LTSSM_ENABLE_ID),245&app_reg->app_ctrl_0);246else247return -EINVAL;248return count;249}250251static ssize_t pcie_gadget_show_int_type(252struct spear_pcie_gadget_config *config,253char *buf)254{255return sprintf(buf, "%s", config->int_type);256}257258static ssize_t pcie_gadget_store_int_type(259struct spear_pcie_gadget_config *config,260const char *buf, size_t count)261{262u32 cap, vec, flags;263ulong vector;264265if (sysfs_streq(buf, "INTA"))266spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1);267268else if (sysfs_streq(buf, "MSI")) {269vector = config->requested_msi;270vec = 0;271while (vector > 1) {272vector /= 2;273vec++;274}275spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 0);276cap = pci_find_own_capability(config, PCI_CAP_ID_MSI);277spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags);278flags &= ~PCI_MSI_FLAGS_QMASK;279flags |= vec << 1;280spear_dbi_write_reg(config, cap + PCI_MSI_FLAGS, 1, flags);281} else282return -EINVAL;283284strcpy(config->int_type, buf);285286return count;287}288289static ssize_t pcie_gadget_show_no_of_msi(290struct spear_pcie_gadget_config *config,291char *buf)292{293struct pcie_app_reg __iomem *app_reg = config->va_app_base;294u32 cap, vec, flags;295ulong vector;296297if ((readl(&app_reg->msg_status) & (1 << CFG_MSI_EN_ID))298!= (1 << CFG_MSI_EN_ID))299vector = 0;300else {301cap = pci_find_own_capability(config, PCI_CAP_ID_MSI);302spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags);303flags &= ~PCI_MSI_FLAGS_QSIZE;304vec = flags >> 4;305vector = 1;306while (vec--)307vector *= 2;308}309config->configured_msi = vector;310311return sprintf(buf, "%lu", vector);312}313314static ssize_t pcie_gadget_store_no_of_msi(315struct spear_pcie_gadget_config *config,316const char *buf, size_t count)317{318if (strict_strtoul(buf, 0, &config->requested_msi))319return -EINVAL;320if (config->requested_msi > 32)321config->requested_msi = 32;322323return count;324}325326static ssize_t pcie_gadget_store_inta(327struct spear_pcie_gadget_config *config,328const char *buf, size_t count)329{330struct pcie_app_reg __iomem *app_reg = config->va_app_base;331ulong en;332333if (strict_strtoul(buf, 0, &en))334return -EINVAL;335336if (en)337writel(readl(&app_reg->app_ctrl_0) | (1 << SYS_INT_ID),338&app_reg->app_ctrl_0);339else340writel(readl(&app_reg->app_ctrl_0) & ~(1 << SYS_INT_ID),341&app_reg->app_ctrl_0);342343return count;344}345346static ssize_t pcie_gadget_store_send_msi(347struct spear_pcie_gadget_config *config,348const char *buf, size_t count)349{350struct pcie_app_reg __iomem *app_reg = config->va_app_base;351ulong vector;352u32 ven_msi;353354if (strict_strtoul(buf, 0, &vector))355return -EINVAL;356357if (!config->configured_msi)358return -EINVAL;359360if (vector >= config->configured_msi)361return -EINVAL;362363ven_msi = readl(&app_reg->ven_msi_1);364ven_msi &= ~VEN_MSI_FUN_NUM_MASK;365ven_msi |= 0 << VEN_MSI_FUN_NUM_ID;366ven_msi &= ~VEN_MSI_TC_MASK;367ven_msi |= 0 << VEN_MSI_TC_ID;368ven_msi &= ~VEN_MSI_VECTOR_MASK;369ven_msi |= vector << VEN_MSI_VECTOR_ID;370371/* generating interrupt for msi vector */372ven_msi |= VEN_MSI_REQ_EN;373writel(ven_msi, &app_reg->ven_msi_1);374udelay(1);375ven_msi &= ~VEN_MSI_REQ_EN;376writel(ven_msi, &app_reg->ven_msi_1);377378return count;379}380381static ssize_t pcie_gadget_show_vendor_id(382struct spear_pcie_gadget_config *config,383char *buf)384{385u32 id;386387spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id);388389return sprintf(buf, "%x", id);390}391392static ssize_t pcie_gadget_store_vendor_id(393struct spear_pcie_gadget_config *config,394const char *buf, size_t count)395{396ulong id;397398if (strict_strtoul(buf, 0, &id))399return -EINVAL;400401spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id);402403return count;404}405406static ssize_t pcie_gadget_show_device_id(407struct spear_pcie_gadget_config *config,408char *buf)409{410u32 id;411412spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id);413414return sprintf(buf, "%x", id);415}416417static ssize_t pcie_gadget_store_device_id(418struct spear_pcie_gadget_config *config,419const char *buf, size_t count)420{421ulong id;422423if (strict_strtoul(buf, 0, &id))424return -EINVAL;425426spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id);427428return count;429}430431static ssize_t pcie_gadget_show_bar0_size(432struct spear_pcie_gadget_config *config,433char *buf)434{435return sprintf(buf, "%lx", config->bar0_size);436}437438static ssize_t pcie_gadget_store_bar0_size(439struct spear_pcie_gadget_config *config,440const char *buf, size_t count)441{442ulong size;443u32 pos, pos1;444u32 no_of_bit = 0;445446if (strict_strtoul(buf, 0, &size))447return -EINVAL;448/* min bar size is 256 */449if (size <= 0x100)450size = 0x100;451/* max bar size is 1MB*/452else if (size >= 0x100000)453size = 0x100000;454else {455pos = 0;456pos1 = 0;457while (pos < 21) {458pos = find_next_bit((ulong *)&size, 21, pos);459if (pos != 21)460pos1 = pos + 1;461pos++;462no_of_bit++;463}464if (no_of_bit == 2)465pos1--;466467size = 1 << pos1;468}469config->bar0_size = size;470spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, size - 1);471472return count;473}474475static ssize_t pcie_gadget_show_bar0_address(476struct spear_pcie_gadget_config *config,477char *buf)478{479struct pcie_app_reg __iomem *app_reg = config->va_app_base;480481u32 address = readl(&app_reg->pim0_mem_addr_start);482483return sprintf(buf, "%x", address);484}485486static ssize_t pcie_gadget_store_bar0_address(487struct spear_pcie_gadget_config *config,488const char *buf, size_t count)489{490struct pcie_app_reg __iomem *app_reg = config->va_app_base;491ulong address;492493if (strict_strtoul(buf, 0, &address))494return -EINVAL;495496address &= ~(config->bar0_size - 1);497if (config->va_bar0_address)498iounmap(config->va_bar0_address);499config->va_bar0_address = ioremap(address, config->bar0_size);500if (!config->va_bar0_address)501return -ENOMEM;502503writel(address, &app_reg->pim0_mem_addr_start);504505return count;506}507508static ssize_t pcie_gadget_show_bar0_rw_offset(509struct spear_pcie_gadget_config *config,510char *buf)511{512return sprintf(buf, "%lx", config->bar0_rw_offset);513}514515static ssize_t pcie_gadget_store_bar0_rw_offset(516struct spear_pcie_gadget_config *config,517const char *buf, size_t count)518{519ulong offset;520521if (strict_strtoul(buf, 0, &offset))522return -EINVAL;523524if (offset % 4)525return -EINVAL;526527config->bar0_rw_offset = offset;528529return count;530}531532static ssize_t pcie_gadget_show_bar0_data(533struct spear_pcie_gadget_config *config,534char *buf)535{536ulong data;537538if (!config->va_bar0_address)539return -ENOMEM;540541data = readl((ulong)config->va_bar0_address + config->bar0_rw_offset);542543return sprintf(buf, "%lx", data);544}545546static ssize_t pcie_gadget_store_bar0_data(547struct spear_pcie_gadget_config *config,548const char *buf, size_t count)549{550ulong data;551552if (strict_strtoul(buf, 0, &data))553return -EINVAL;554555if (!config->va_bar0_address)556return -ENOMEM;557558writel(data, (ulong)config->va_bar0_address + config->bar0_rw_offset);559560return count;561}562563/*564* Attribute definitions.565*/566567#define PCIE_GADGET_TARGET_ATTR_RO(_name) \568static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \569__CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL)570571#define PCIE_GADGET_TARGET_ATTR_WO(_name) \572static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \573__CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name)574575#define PCIE_GADGET_TARGET_ATTR_RW(_name) \576static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \577__CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \578pcie_gadget_store_##_name)579PCIE_GADGET_TARGET_ATTR_RW(link);580PCIE_GADGET_TARGET_ATTR_RW(int_type);581PCIE_GADGET_TARGET_ATTR_RW(no_of_msi);582PCIE_GADGET_TARGET_ATTR_WO(inta);583PCIE_GADGET_TARGET_ATTR_WO(send_msi);584PCIE_GADGET_TARGET_ATTR_RW(vendor_id);585PCIE_GADGET_TARGET_ATTR_RW(device_id);586PCIE_GADGET_TARGET_ATTR_RW(bar0_size);587PCIE_GADGET_TARGET_ATTR_RW(bar0_address);588PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset);589PCIE_GADGET_TARGET_ATTR_RW(bar0_data);590591static struct configfs_attribute *pcie_gadget_target_attrs[] = {592&pcie_gadget_target_link.attr,593&pcie_gadget_target_int_type.attr,594&pcie_gadget_target_no_of_msi.attr,595&pcie_gadget_target_inta.attr,596&pcie_gadget_target_send_msi.attr,597&pcie_gadget_target_vendor_id.attr,598&pcie_gadget_target_device_id.attr,599&pcie_gadget_target_bar0_size.attr,600&pcie_gadget_target_bar0_address.attr,601&pcie_gadget_target_bar0_rw_offset.attr,602&pcie_gadget_target_bar0_data.attr,603NULL,604};605606static struct pcie_gadget_target *to_target(struct config_item *item)607{608return item ?609container_of(to_configfs_subsystem(to_config_group(item)),610struct pcie_gadget_target, subsys) : NULL;611}612613/*614* Item operations and type for pcie_gadget_target.615*/616617static ssize_t pcie_gadget_target_attr_show(struct config_item *item,618struct configfs_attribute *attr,619char *buf)620{621ssize_t ret = -EINVAL;622struct pcie_gadget_target *target = to_target(item);623struct pcie_gadget_target_attr *t_attr =624container_of(attr, struct pcie_gadget_target_attr, attr);625626if (t_attr->show)627ret = t_attr->show(&target->config, buf);628return ret;629}630631static ssize_t pcie_gadget_target_attr_store(struct config_item *item,632struct configfs_attribute *attr,633const char *buf,634size_t count)635{636ssize_t ret = -EINVAL;637struct pcie_gadget_target *target = to_target(item);638struct pcie_gadget_target_attr *t_attr =639container_of(attr, struct pcie_gadget_target_attr, attr);640641if (t_attr->store)642ret = t_attr->store(&target->config, buf, count);643return ret;644}645646static struct configfs_item_operations pcie_gadget_target_item_ops = {647.show_attribute = pcie_gadget_target_attr_show,648.store_attribute = pcie_gadget_target_attr_store,649};650651static struct config_item_type pcie_gadget_target_type = {652.ct_attrs = pcie_gadget_target_attrs,653.ct_item_ops = &pcie_gadget_target_item_ops,654.ct_owner = THIS_MODULE,655};656657static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config)658{659struct pcie_app_reg __iomem *app_reg = config->va_app_base;660661/*setup registers for outbound translation */662663writel(config->base, &app_reg->in0_mem_addr_start);664writel(app_reg->in0_mem_addr_start + IN0_MEM_SIZE,665&app_reg->in0_mem_addr_limit);666writel(app_reg->in0_mem_addr_limit + 1, &app_reg->in1_mem_addr_start);667writel(app_reg->in1_mem_addr_start + IN1_MEM_SIZE,668&app_reg->in1_mem_addr_limit);669writel(app_reg->in1_mem_addr_limit + 1, &app_reg->in_io_addr_start);670writel(app_reg->in_io_addr_start + IN_IO_SIZE,671&app_reg->in_io_addr_limit);672writel(app_reg->in_io_addr_limit + 1, &app_reg->in_cfg0_addr_start);673writel(app_reg->in_cfg0_addr_start + IN_CFG0_SIZE,674&app_reg->in_cfg0_addr_limit);675writel(app_reg->in_cfg0_addr_limit + 1, &app_reg->in_cfg1_addr_start);676writel(app_reg->in_cfg1_addr_start + IN_CFG1_SIZE,677&app_reg->in_cfg1_addr_limit);678writel(app_reg->in_cfg1_addr_limit + 1, &app_reg->in_msg_addr_start);679writel(app_reg->in_msg_addr_start + IN_MSG_SIZE,680&app_reg->in_msg_addr_limit);681682writel(app_reg->in0_mem_addr_start, &app_reg->pom0_mem_addr_start);683writel(app_reg->in1_mem_addr_start, &app_reg->pom1_mem_addr_start);684writel(app_reg->in_io_addr_start, &app_reg->pom_io_addr_start);685686/*setup registers for inbound translation */687688/* Keep AORAM mapped at BAR0 as default */689config->bar0_size = INBOUND_ADDR_MASK + 1;690spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, INBOUND_ADDR_MASK);691spear_dbi_write_reg(config, PCI_BASE_ADDRESS_0, 4, 0xC);692config->va_bar0_address = ioremap(SPEAR13XX_SYSRAM1_BASE,693config->bar0_size);694695writel(SPEAR13XX_SYSRAM1_BASE, &app_reg->pim0_mem_addr_start);696writel(0, &app_reg->pim1_mem_addr_start);697writel(INBOUND_ADDR_MASK + 1, &app_reg->mem0_addr_offset_limit);698699writel(0x0, &app_reg->pim_io_addr_start);700writel(0x0, &app_reg->pim_io_addr_start);701writel(0x0, &app_reg->pim_rom_addr_start);702703writel(DEVICE_TYPE_EP | (1 << MISCTRL_EN_ID)704| ((u32)1 << REG_TRANSLATION_ENABLE),705&app_reg->app_ctrl_0);706/* disable all rx interrupts */707writel(0, &app_reg->int_mask);708709/* Select INTA as default*/710spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1);711}712713static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev)714{715struct resource *res0, *res1;716unsigned int status = 0;717int irq;718struct clk *clk;719static struct pcie_gadget_target *target;720struct spear_pcie_gadget_config *config;721struct config_item *cg_item;722struct configfs_subsystem *subsys;723724/* get resource for application registers*/725726res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);727if (!res0) {728dev_err(&pdev->dev, "no resource defined\n");729return -EBUSY;730}731if (!request_mem_region(res0->start, resource_size(res0),732pdev->name)) {733dev_err(&pdev->dev, "pcie gadget region already claimed\n");734return -EBUSY;735}736/* get resource for dbi registers*/737738res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);739if (!res1) {740dev_err(&pdev->dev, "no resource defined\n");741goto err_rel_res0;742}743if (!request_mem_region(res1->start, resource_size(res1),744pdev->name)) {745dev_err(&pdev->dev, "pcie gadget region already claimed\n");746goto err_rel_res0;747}748749target = kzalloc(sizeof(*target), GFP_KERNEL);750if (!target) {751dev_err(&pdev->dev, "out of memory\n");752status = -ENOMEM;753goto err_rel_res;754}755756cg_item = &target->subsys.su_group.cg_item;757sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id);758cg_item->ci_type = &pcie_gadget_target_type;759config = &target->config;760config->va_app_base = (void __iomem *)ioremap(res0->start,761resource_size(res0));762if (!config->va_app_base) {763dev_err(&pdev->dev, "ioremap fail\n");764status = -ENOMEM;765goto err_kzalloc;766}767768config->base = (void __iomem *)res1->start;769770config->va_dbi_base = (void __iomem *)ioremap(res1->start,771resource_size(res1));772if (!config->va_dbi_base) {773dev_err(&pdev->dev, "ioremap fail\n");774status = -ENOMEM;775goto err_iounmap_app;776}777778dev_set_drvdata(&pdev->dev, target);779780irq = platform_get_irq(pdev, 0);781if (irq < 0) {782dev_err(&pdev->dev, "no update irq?\n");783status = irq;784goto err_iounmap;785}786787status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL);788if (status) {789dev_err(&pdev->dev,790"pcie gadget interrupt IRQ%d already claimed\n", irq);791goto err_iounmap;792}793794/* Register configfs hooks */795subsys = &target->subsys;796config_group_init(&subsys->su_group);797mutex_init(&subsys->su_mutex);798status = configfs_register_subsystem(subsys);799if (status)800goto err_irq;801802/*803* init basic pcie application registers804* do not enable clock if it is PCIE0.Ideally , all controller should805* have been independent from others with respect to clock. But PCIE1806* and 2 depends on PCIE0.So PCIE0 clk is provided during board init.807*/808if (pdev->id == 1) {809/*810* Ideally CFG Clock should have been also enabled here. But811* it is done currently during board init routne812*/813clk = clk_get_sys("pcie1", NULL);814if (IS_ERR(clk)) {815pr_err("%s:couldn't get clk for pcie1\n", __func__);816goto err_irq;817}818if (clk_enable(clk)) {819pr_err("%s:couldn't enable clk for pcie1\n", __func__);820goto err_irq;821}822} else if (pdev->id == 2) {823/*824* Ideally CFG Clock should have been also enabled here. But825* it is done currently during board init routne826*/827clk = clk_get_sys("pcie2", NULL);828if (IS_ERR(clk)) {829pr_err("%s:couldn't get clk for pcie2\n", __func__);830goto err_irq;831}832if (clk_enable(clk)) {833pr_err("%s:couldn't enable clk for pcie2\n", __func__);834goto err_irq;835}836}837spear13xx_pcie_device_init(config);838839return 0;840err_irq:841free_irq(irq, NULL);842err_iounmap:843iounmap(config->va_dbi_base);844err_iounmap_app:845iounmap(config->va_app_base);846err_kzalloc:847kfree(target);848err_rel_res:849release_mem_region(res1->start, resource_size(res1));850err_rel_res0:851release_mem_region(res0->start, resource_size(res0));852return status;853}854855static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev)856{857struct resource *res0, *res1;858static struct pcie_gadget_target *target;859struct spear_pcie_gadget_config *config;860int irq;861862res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);863res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);864irq = platform_get_irq(pdev, 0);865target = dev_get_drvdata(&pdev->dev);866config = &target->config;867868free_irq(irq, NULL);869iounmap(config->va_dbi_base);870iounmap(config->va_app_base);871release_mem_region(res1->start, resource_size(res1));872release_mem_region(res0->start, resource_size(res0));873configfs_unregister_subsystem(&target->subsys);874kfree(target);875876return 0;877}878879static void spear_pcie_gadget_shutdown(struct platform_device *pdev)880{881}882883static struct platform_driver spear_pcie_gadget_driver = {884.probe = spear_pcie_gadget_probe,885.remove = spear_pcie_gadget_remove,886.shutdown = spear_pcie_gadget_shutdown,887.driver = {888.name = "pcie-gadget-spear",889.bus = &platform_bus_type890},891};892893static int __init spear_pcie_gadget_init(void)894{895return platform_driver_register(&spear_pcie_gadget_driver);896}897module_init(spear_pcie_gadget_init);898899static void __exit spear_pcie_gadget_exit(void)900{901platform_driver_unregister(&spear_pcie_gadget_driver);902}903module_exit(spear_pcie_gadget_exit);904905MODULE_ALIAS("pcie-gadget-spear");906MODULE_AUTHOR("Pratyush Anand");907MODULE_LICENSE("GPL");908909910