Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/misc/atmel-ssc.c
15109 views
1
/*
2
* Atmel SSC driver
3
*
4
* Copyright (C) 2007 Atmel Corporation
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
9
*/
10
11
#include <linux/platform_device.h>
12
#include <linux/list.h>
13
#include <linux/clk.h>
14
#include <linux/err.h>
15
#include <linux/io.h>
16
#include <linux/spinlock.h>
17
#include <linux/atmel-ssc.h>
18
#include <linux/slab.h>
19
20
/* Serialize access to ssc_list and user count */
21
static DEFINE_SPINLOCK(user_lock);
22
static LIST_HEAD(ssc_list);
23
24
struct ssc_device *ssc_request(unsigned int ssc_num)
25
{
26
int ssc_valid = 0;
27
struct ssc_device *ssc;
28
29
spin_lock(&user_lock);
30
list_for_each_entry(ssc, &ssc_list, list) {
31
if (ssc->pdev->id == ssc_num) {
32
ssc_valid = 1;
33
break;
34
}
35
}
36
37
if (!ssc_valid) {
38
spin_unlock(&user_lock);
39
pr_err("ssc: ssc%d platform device is missing\n", ssc_num);
40
return ERR_PTR(-ENODEV);
41
}
42
43
if (ssc->user) {
44
spin_unlock(&user_lock);
45
dev_dbg(&ssc->pdev->dev, "module busy\n");
46
return ERR_PTR(-EBUSY);
47
}
48
ssc->user++;
49
spin_unlock(&user_lock);
50
51
clk_enable(ssc->clk);
52
53
return ssc;
54
}
55
EXPORT_SYMBOL(ssc_request);
56
57
void ssc_free(struct ssc_device *ssc)
58
{
59
spin_lock(&user_lock);
60
if (ssc->user) {
61
ssc->user--;
62
clk_disable(ssc->clk);
63
} else {
64
dev_dbg(&ssc->pdev->dev, "device already free\n");
65
}
66
spin_unlock(&user_lock);
67
}
68
EXPORT_SYMBOL(ssc_free);
69
70
static int __init ssc_probe(struct platform_device *pdev)
71
{
72
int retval = 0;
73
struct resource *regs;
74
struct ssc_device *ssc;
75
76
ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL);
77
if (!ssc) {
78
dev_dbg(&pdev->dev, "out of memory\n");
79
retval = -ENOMEM;
80
goto out;
81
}
82
83
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
84
if (!regs) {
85
dev_dbg(&pdev->dev, "no mmio resource defined\n");
86
retval = -ENXIO;
87
goto out_free;
88
}
89
90
ssc->clk = clk_get(&pdev->dev, "pclk");
91
if (IS_ERR(ssc->clk)) {
92
dev_dbg(&pdev->dev, "no pclk clock defined\n");
93
retval = -ENXIO;
94
goto out_free;
95
}
96
97
ssc->pdev = pdev;
98
ssc->regs = ioremap(regs->start, regs->end - regs->start + 1);
99
if (!ssc->regs) {
100
dev_dbg(&pdev->dev, "ioremap failed\n");
101
retval = -EINVAL;
102
goto out_clk;
103
}
104
105
/* disable all interrupts */
106
clk_enable(ssc->clk);
107
ssc_writel(ssc->regs, IDR, ~0UL);
108
ssc_readl(ssc->regs, SR);
109
clk_disable(ssc->clk);
110
111
ssc->irq = platform_get_irq(pdev, 0);
112
if (!ssc->irq) {
113
dev_dbg(&pdev->dev, "could not get irq\n");
114
retval = -ENXIO;
115
goto out_unmap;
116
}
117
118
spin_lock(&user_lock);
119
list_add_tail(&ssc->list, &ssc_list);
120
spin_unlock(&user_lock);
121
122
platform_set_drvdata(pdev, ssc);
123
124
dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
125
ssc->regs, ssc->irq);
126
127
goto out;
128
129
out_unmap:
130
iounmap(ssc->regs);
131
out_clk:
132
clk_put(ssc->clk);
133
out_free:
134
kfree(ssc);
135
out:
136
return retval;
137
}
138
139
static int __devexit ssc_remove(struct platform_device *pdev)
140
{
141
struct ssc_device *ssc = platform_get_drvdata(pdev);
142
143
spin_lock(&user_lock);
144
iounmap(ssc->regs);
145
clk_put(ssc->clk);
146
list_del(&ssc->list);
147
kfree(ssc);
148
spin_unlock(&user_lock);
149
150
return 0;
151
}
152
153
static struct platform_driver ssc_driver = {
154
.remove = __devexit_p(ssc_remove),
155
.driver = {
156
.name = "ssc",
157
.owner = THIS_MODULE,
158
},
159
};
160
161
static int __init ssc_init(void)
162
{
163
return platform_driver_probe(&ssc_driver, ssc_probe);
164
}
165
module_init(ssc_init);
166
167
static void __exit ssc_exit(void)
168
{
169
platform_driver_unregister(&ssc_driver);
170
}
171
module_exit(ssc_exit);
172
173
MODULE_AUTHOR("Hans-Christian Egtvedt <[email protected]>");
174
MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91");
175
MODULE_LICENSE("GPL");
176
MODULE_ALIAS("platform:ssc");
177
178