pxa2xx_spi_pci.c 4.0 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * CE4100's SPI device is more or less the same one as found on PXA
 *
 */
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/spi/pxa2xx_spi.h>

10
struct ce4100_info {
11
	struct ssp_device ssp;
12
	struct platform_device *spi_pdev;
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
};

static DEFINE_MUTEX(ssp_lock);
static LIST_HEAD(ssp_list);

struct ssp_device *pxa_ssp_request(int port, const char *label)
{
	struct ssp_device *ssp = NULL;

	mutex_lock(&ssp_lock);

	list_for_each_entry(ssp, &ssp_list, node) {
		if (ssp->port_id == port && ssp->use_count == 0) {
			ssp->use_count++;
			ssp->label = label;
			break;
		}
	}

	mutex_unlock(&ssp_lock);

	if (&ssp->node == &ssp_list)
		return NULL;

	return ssp;
}
EXPORT_SYMBOL_GPL(pxa_ssp_request);

void pxa_ssp_free(struct ssp_device *ssp)
{
	mutex_lock(&ssp_lock);
	if (ssp->use_count) {
		ssp->use_count--;
		ssp->label = NULL;
	} else
		dev_err(&ssp->pdev->dev, "device already free\n");
	mutex_unlock(&ssp_lock);
}
EXPORT_SYMBOL_GPL(pxa_ssp_free);

static int __devinit ce4100_spi_probe(struct pci_dev *dev,
		const struct pci_device_id *ent)
{
	int ret;
	resource_size_t phys_beg;
	resource_size_t phys_len;
59
	struct ce4100_info *spi_info;
60
	struct platform_device *pdev;
61
	struct pxa2xx_spi_master spi_pdata;
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
	struct ssp_device *ssp;

	ret = pci_enable_device(dev);
	if (ret)
		return ret;

	phys_beg = pci_resource_start(dev, 0);
	phys_len = pci_resource_len(dev, 0);

	if (!request_mem_region(phys_beg, phys_len,
				"CE4100 SPI")) {
		dev_err(&dev->dev, "Can't request register space.\n");
		ret = -EBUSY;
		return ret;
	}

78
	pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
79
	spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
80
	if (!pdev || !spi_info ) {
81
		ret = -ENOMEM;
82
		goto err_nomem;
83
	}
84 85
	memset(&spi_pdata, 0, sizeof(spi_pdata));
	spi_pdata.num_chipselect = dev->devfn;
86

87 88 89
	ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
	if (ret)
		goto err_nomem;
90

91
	pdev->dev.parent = &dev->dev;
92 93 94
#ifdef CONFIG_OF
	pdev->dev.of_node = dev->dev.of_node;
#endif
95
	ssp = &spi_info->ssp;
96 97 98 99 100
	ssp->phys_base = pci_resource_start(dev, 0);
	ssp->mmio_base = ioremap(phys_beg, phys_len);
	if (!ssp->mmio_base) {
		dev_err(&pdev->dev, "failed to ioremap() registers\n");
		ret = -EIO;
101
		goto err_nomem;
102 103 104 105 106 107 108 109 110 111 112
	}
	ssp->irq = dev->irq;
	ssp->port_id = pdev->id;
	ssp->type = PXA25x_SSP;

	mutex_lock(&ssp_lock);
	list_add(&ssp->node, &ssp_list);
	mutex_unlock(&ssp_lock);

	pci_set_drvdata(dev, spi_info);

113
	ret = platform_device_add(pdev);
114 115 116 117 118 119 120 121 122 123 124 125
	if (ret)
		goto err_dev_add;

	return ret;

err_dev_add:
	pci_set_drvdata(dev, NULL);
	mutex_lock(&ssp_lock);
	list_del(&ssp->node);
	mutex_unlock(&ssp_lock);
	iounmap(ssp->mmio_base);

126
err_nomem:
127
	release_mem_region(phys_beg, phys_len);
128 129
	platform_device_put(pdev);
	kfree(spi_info);
130 131 132 133 134
	return ret;
}

static void __devexit ce4100_spi_remove(struct pci_dev *dev)
{
135
	struct ce4100_info *spi_info;
136 137 138 139
	struct ssp_device *ssp;

	spi_info = pci_get_drvdata(dev);
	ssp = &spi_info->ssp;
140
	platform_device_unregister(spi_info->spi_pdev);
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182

	iounmap(ssp->mmio_base);
	release_mem_region(pci_resource_start(dev, 0),
			pci_resource_len(dev, 0));

	mutex_lock(&ssp_lock);
	list_del(&ssp->node);
	mutex_unlock(&ssp_lock);

	pci_set_drvdata(dev, NULL);
	pci_disable_device(dev);
	kfree(spi_info);
}

static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
	{ },
};
MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);

static struct pci_driver ce4100_spi_driver = {
	.name           = "ce4100_spi",
	.id_table       = ce4100_spi_devices,
	.probe          = ce4100_spi_probe,
	.remove         = __devexit_p(ce4100_spi_remove),
};

static int __init ce4100_spi_init(void)
{
	return pci_register_driver(&ce4100_spi_driver);
}
module_init(ce4100_spi_init);

static void __exit ce4100_spi_exit(void)
{
	pci_unregister_driver(&ce4100_spi_driver);
}
module_exit(ce4100_spi_exit);

MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");