From 15bbb553d433abd7ad832db965cf8ce4f5991238 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Sun, 16 Mar 2014 20:36:53 +0100 Subject: [PATCH] bcwc_pcie: Add pci driver skeleton Register pci driver, irq handler, map pci bars. You know the drill. Signed-off-by: Patrik Jakobsson --- Makefile | 15 ++++ bcwc_drv.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++ bcwc_drv.h | 35 ++++++++ 3 files changed, 284 insertions(+) create mode 100644 Makefile create mode 100644 bcwc_drv.c create mode 100644 bcwc_drv.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0ad7300 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +bcwc_pcie-objs := bcwc_drv.o +obj-m := bcwc_pcie.o + +KVERSION := $(shell uname -r) +KDIR := /lib/modules/$(KVERSION)/build +PWD := $(shell pwd) + +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean + +install: + $(MAKE) -C $(KDIR) M=$(PWD) modules_install diff --git a/bcwc_drv.c b/bcwc_drv.c new file mode 100644 index 0000000..7c6cd49 --- /dev/null +++ b/bcwc_drv.c @@ -0,0 +1,234 @@ +/* + * Broadcom PCIe 1570 webcam driver + * + * Copyright (C) 2014 Patrik Jakobsson (patrik.r.jakobsson@gmail.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include "bcwc_drv.h" + +static int bcwc_pci_reserve_mem(struct bcwc_private *dev_priv) +{ + unsigned long start; + unsigned long len; + int ret; + + /* Reserve resources */ + ret = pci_request_region(dev_priv->pdev, BCWC_PCI_LINK_IO, "Link IO"); + if (ret) { + dev_err(&dev_priv->pdev->dev, "Failed to request Link IO\n"); + return ret; + } + + ret = pci_request_region(dev_priv->pdev, BCWC_PCI_DEV_IO, "Device IO"); + if (ret) { + dev_err(&dev_priv->pdev->dev, "Failed to request Device IO\n"); + return ret; + } + + /* Link IO */ + start = pci_resource_start(dev_priv->pdev, BCWC_PCI_LINK_IO); + len = pci_resource_len(dev_priv->pdev, BCWC_PCI_LINK_IO); + dev_priv->link_io = ioremap_nocache(start, len); + + /* Device IO */ + start = pci_resource_start(dev_priv->pdev, BCWC_PCI_DEV_IO); + len = pci_resource_len(dev_priv->pdev, BCWC_PCI_DEV_IO); + dev_priv->dev_io = ioremap_nocache(start, len); + + return 0; +} + +static void bcwc_irq_work(struct work_struct *work) +{ +} + +static irqreturn_t bcwc_irq_handler(int irq, void *arg) +{ + struct bcwc_private *dev_priv = arg; + + schedule_work(&dev_priv->irq_work); + + return IRQ_HANDLED; +} + +static int bcwc_irq_enable(struct bcwc_private *dev_priv) +{ + int ret; + + ret = request_irq(dev_priv->pdev->irq, bcwc_irq_handler, IRQF_SHARED, + KBUILD_MODNAME, (void *)dev_priv); + + if (ret) + dev_err(&dev_priv->pdev->dev, "Failed to request IRQ\n"); + + return ret; +} + +static void bcwc_irq_disable(struct bcwc_private *dev_priv) +{ + free_irq(dev_priv->pdev->irq, dev_priv); +} + +static int bcwc_pci_set_dma_mask(struct bcwc_private *dev_priv, + unsigned int mask) +{ + int ret; + + ret = pci_set_dma_mask(dev_priv->pdev, DMA_BIT_MASK(mask)); + if (ret) { + dev_err(&dev_priv->pdev->dev, "Failed to set %u pci dma mask\n", + mask); + return ret; + } + + dev_priv->dma_mask = mask; + + return 0; +} + +static int bcwc_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *entry) +{ + struct bcwc_private *dev_priv; + int ret; + + dev_info(&pdev->dev, "Found Broadcom PCIe webcam with device id: %x\n", + pdev->device); + + dev_priv = kzalloc(sizeof(struct bcwc_private), GFP_KERNEL); + if (!dev_priv) { + dev_err(&pdev->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + dev_priv->pdev = pdev; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to enable device\n"); + goto fail_free; + } + + ret = bcwc_pci_reserve_mem(dev_priv); + if (ret) + goto fail_enable; + + ret = pci_enable_msi(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to enable MSI\n"); + goto fail_enable; + } + + INIT_WORK(&dev_priv->irq_work, bcwc_irq_work); + + ret = bcwc_irq_enable(dev_priv); + if (ret) + goto fail_msi; + + ret = bcwc_pci_set_dma_mask(dev_priv, 64); + if (ret) + ret = bcwc_pci_set_dma_mask(dev_priv, 32); + + if (ret) + goto fail_msi; + + dev_info(&pdev->dev, "Setting %ubit DMA mask\n", dev_priv->dma_mask); + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(dev_priv->dma_mask)); + + pci_set_master(pdev); + pci_set_drvdata(pdev, dev_priv); + + return 0; +fail_msi: + pci_disable_msi(pdev); +fail_enable: + pci_disable_device(pdev); +fail_free: + kfree(dev_priv); + return ret; +} + +static void bcwc_pci_remove(struct pci_dev *pdev) +{ + struct bcwc_private *dev_priv; + + dev_priv = pci_get_drvdata(pdev); + + if (dev_priv) { + bcwc_irq_disable(dev_priv); + pci_disable_msi(pdev); + + if (dev_priv->link_io) + iounmap(dev_priv->link_io); + if (dev_priv->dev_io) + iounmap(dev_priv->dev_io); + + pci_release_region(pdev, BCWC_PCI_DEV_IO); + pci_release_region(pdev, BCWC_PCI_LINK_IO); + } + + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int bcwc_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + return 0; +} + +static int bcwc_pci_resume(struct pci_dev *pdev) +{ + return 0; +} +#endif /* CONFIG_PM */ + +static const struct pci_device_id bcwc_pci_id_table[] = { + { PCI_VDEVICE(BROADCOM, 0x1570), 4 }, + { 0, }, +}; + +static struct pci_driver bcwc_pci_driver = { + .name = KBUILD_MODNAME, + .probe = bcwc_pci_probe, + .remove = bcwc_pci_remove, + .id_table = bcwc_pci_id_table, +#ifdef CONFIG_PM + .suspend = bcwc_pci_suspend, + .resume = bcwc_pci_resume, +#endif +}; + +static int __init bcwc_init(void) +{ + int ret = 0; + + ret = pci_register_driver(&bcwc_pci_driver); + + if (ret) + pr_err("Couldn't find any devices (ret=%d)\n", ret); + + return ret; +} + +static void __exit bcwc_exit(void) +{ + pci_unregister_driver(&bcwc_pci_driver); +} + +module_init(bcwc_init); +module_exit(bcwc_exit); + +MODULE_AUTHOR("Patrik Jakobsson "); +MODULE_DESCRIPTION("Broadcom PCIe 1570 webcam driver"); +MODULE_LICENSE("GPL"); diff --git a/bcwc_drv.h b/bcwc_drv.h new file mode 100644 index 0000000..dadc167 --- /dev/null +++ b/bcwc_drv.h @@ -0,0 +1,35 @@ +/* + * Broadcom PCIe 1570 webcam driver + * + * Copyright (C) 2014 Patrik Jakobsson (patrik.r.jakobsson@gmail.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + */ + +#ifndef _BCWC_PCIE_H +#define _PCWC_PCIE_H + +#include + +#define BCWC_PCI_LINK_IO 0 +#define BCWC_PCI_DEV_MEM 1 +#define BCWC_PCI_DEV_IO 2 + +struct bcwc_private { + struct pci_dev *pdev; + unsigned int dma_mask; + + /* Mapped PCI resources */ + void *link_io; + void *dev_io; + + struct work_struct irq_work; + + /* Hardware info */ + u32 core_clk; +}; + +#endif