• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/spi/
1/*
2 * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core
3 *
4 * Copyright (c) 2010, Octasic semiconductor.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 */
10
11#include <linux/clk.h>
12#include <linux/interrupt.h>
13#include <linux/platform_device.h>
14#include <linux/slab.h>
15#include <linux/spi/dw_spi.h>
16#include <linux/spi/spi.h>
17
18#define DRIVER_NAME "dw_spi_mmio"
19
20struct dw_spi_mmio {
21	struct dw_spi  dws;
22	struct clk     *clk;
23};
24
25static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
26{
27	struct dw_spi_mmio *dwsmmio;
28	struct dw_spi *dws;
29	struct resource *mem, *ioarea;
30	int ret;
31
32	dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL);
33	if (!dwsmmio) {
34		ret = -ENOMEM;
35		goto err_end;
36	}
37
38	dws = &dwsmmio->dws;
39
40	/* Get basic io resource and map it */
41	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
42	if (!mem) {
43		dev_err(&pdev->dev, "no mem resource?\n");
44		ret = -EINVAL;
45		goto err_kfree;
46	}
47
48	ioarea = request_mem_region(mem->start, resource_size(mem),
49			pdev->name);
50	if (!ioarea) {
51		dev_err(&pdev->dev, "SPI region already claimed\n");
52		ret = -EBUSY;
53		goto err_kfree;
54	}
55
56	dws->regs = ioremap_nocache(mem->start, resource_size(mem));
57	if (!dws->regs) {
58		dev_err(&pdev->dev, "SPI region already mapped\n");
59		ret = -ENOMEM;
60		goto err_release_reg;
61	}
62
63	dws->irq = platform_get_irq(pdev, 0);
64	if (dws->irq < 0) {
65		dev_err(&pdev->dev, "no irq resource?\n");
66		ret = dws->irq; /* -ENXIO */
67		goto err_unmap;
68	}
69
70	dwsmmio->clk = clk_get(&pdev->dev, NULL);
71	if (!dwsmmio->clk) {
72		ret = -ENODEV;
73		goto err_irq;
74	}
75	clk_enable(dwsmmio->clk);
76
77	dws->parent_dev = &pdev->dev;
78	dws->bus_num = 0;
79	dws->num_cs = 4;
80	dws->max_freq = clk_get_rate(dwsmmio->clk);
81
82	ret = dw_spi_add_host(dws);
83	if (ret)
84		goto err_clk;
85
86	platform_set_drvdata(pdev, dwsmmio);
87	return 0;
88
89err_clk:
90	clk_disable(dwsmmio->clk);
91	clk_put(dwsmmio->clk);
92	dwsmmio->clk = NULL;
93err_irq:
94	free_irq(dws->irq, dws);
95err_unmap:
96	iounmap(dws->regs);
97err_release_reg:
98	release_mem_region(mem->start, resource_size(mem));
99err_kfree:
100	kfree(dwsmmio);
101err_end:
102	return ret;
103}
104
105static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
106{
107	struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
108	struct resource *mem;
109
110	platform_set_drvdata(pdev, NULL);
111
112	clk_disable(dwsmmio->clk);
113	clk_put(dwsmmio->clk);
114	dwsmmio->clk = NULL;
115
116	free_irq(dwsmmio->dws.irq, &dwsmmio->dws);
117	dw_spi_remove_host(&dwsmmio->dws);
118	iounmap(dwsmmio->dws.regs);
119	kfree(dwsmmio);
120
121	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
122	release_mem_region(mem->start, resource_size(mem));
123	return 0;
124}
125
126static struct platform_driver dw_spi_mmio_driver = {
127	.remove		= __devexit_p(dw_spi_mmio_remove),
128	.driver		= {
129		.name	= DRIVER_NAME,
130		.owner	= THIS_MODULE,
131	},
132};
133
134static int __init dw_spi_mmio_init(void)
135{
136	return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe);
137}
138module_init(dw_spi_mmio_init);
139
140static void __exit dw_spi_mmio_exit(void)
141{
142	platform_driver_unregister(&dw_spi_mmio_driver);
143}
144module_exit(dw_spi_mmio_exit);
145
146MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
147MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
148MODULE_LICENSE("GPL v2");
149