aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/atmel-ssc.c174
-rw-r--r--include/linux/atmel-ssc.h312
4 files changed, 499 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 73e248fb2ff1..346c44eff95e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -203,4 +203,16 @@ config THINKPAD_ACPI_BAY
203 If you are not sure, say Y here. 203 If you are not sure, say Y here.
204 204
205 205
206config ATMEL_SSC
207 tristate "Device driver for Atmel SSC peripheral"
208 depends on AVR32 || ARCH_AT91
209 ---help---
210 This option enables device driver support for Atmel Syncronized
211 Serial Communication peripheral (SSC).
212
213 The SSC peripheral supports a wide variety of serial frame based
214 communications, i.e. I2S, SPI, etc.
215
216 If unsure, say N.
217
206endif # MISC_DEVICES 218endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b5ce0e3dba86..a24c61475c2f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ 7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
9obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 9obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
10obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
10obj-$(CONFIG_LKDTM) += lkdtm.o 11obj-$(CONFIG_LKDTM) += lkdtm.o
11obj-$(CONFIG_TIFM_CORE) += tifm_core.o 12obj-$(CONFIG_TIFM_CORE) += tifm_core.o
12obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o 13obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
new file mode 100644
index 000000000000..058ccac700d0
--- /dev/null
+++ b/drivers/misc/atmel-ssc.c
@@ -0,0 +1,174 @@
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/list.h>
17#include <linux/spinlock.h>
18#include <linux/atmel-ssc.h>
19
20/* Serialize access to ssc_list and user count */
21static DEFINE_SPINLOCK(user_lock);
22static LIST_HEAD(ssc_list);
23
24struct 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 dev_dbg(&ssc->pdev->dev, "could not find requested device\n");
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}
55EXPORT_SYMBOL(ssc_request);
56
57void 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}
68EXPORT_SYMBOL(ssc_free);
69
70static 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
129out_unmap:
130 iounmap(ssc->regs);
131out_clk:
132 clk_put(ssc->clk);
133out_free:
134 kfree(ssc);
135out:
136 return retval;
137}
138
139static 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
153static struct platform_driver ssc_driver = {
154 .remove = __devexit_p(ssc_remove),
155 .driver = {
156 .name = "ssc",
157 },
158};
159
160static int __init ssc_init(void)
161{
162 return platform_driver_probe(&ssc_driver, ssc_probe);
163}
164module_init(ssc_init);
165
166static void __exit ssc_exit(void)
167{
168 platform_driver_unregister(&ssc_driver);
169}
170module_exit(ssc_exit);
171
172MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
173MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91");
174MODULE_LICENSE("GPL");
diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
new file mode 100644
index 000000000000..06023393fba9
--- /dev/null
+++ b/include/linux/atmel-ssc.h
@@ -0,0 +1,312 @@
1#ifndef __INCLUDE_ATMEL_SSC_H
2#define __INCLUDE_ATMEL_SSC_H
3
4#include <linux/platform_device.h>
5#include <linux/list.h>
6
7struct ssc_device {
8 struct list_head list;
9 void __iomem *regs;
10 struct platform_device *pdev;
11 struct clk *clk;
12 int user;
13 int irq;
14};
15
16struct ssc_device * __must_check ssc_request(unsigned int ssc_num);
17void ssc_free(struct ssc_device *ssc);
18
19/* SSC register offsets */
20
21/* SSC Control Register */
22#define SSC_CR 0x00000000
23#define SSC_CR_RXDIS_SIZE 1
24#define SSC_CR_RXDIS_OFFSET 1
25#define SSC_CR_RXEN_SIZE 1
26#define SSC_CR_RXEN_OFFSET 0
27#define SSC_CR_SWRST_SIZE 1
28#define SSC_CR_SWRST_OFFSET 15
29#define SSC_CR_TXDIS_SIZE 1
30#define SSC_CR_TXDIS_OFFSET 9
31#define SSC_CR_TXEN_SIZE 1
32#define SSC_CR_TXEN_OFFSET 8
33
34/* SSC Clock Mode Register */
35#define SSC_CMR 0x00000004
36#define SSC_CMR_DIV_SIZE 12
37#define SSC_CMR_DIV_OFFSET 0
38
39/* SSC Receive Clock Mode Register */
40#define SSC_RCMR 0x00000010
41#define SSC_RCMR_CKG_SIZE 2
42#define SSC_RCMR_CKG_OFFSET 6
43#define SSC_RCMR_CKI_SIZE 1
44#define SSC_RCMR_CKI_OFFSET 5
45#define SSC_RCMR_CKO_SIZE 3
46#define SSC_RCMR_CKO_OFFSET 2
47#define SSC_RCMR_CKS_SIZE 2
48#define SSC_RCMR_CKS_OFFSET 0
49#define SSC_RCMR_PERIOD_SIZE 8
50#define SSC_RCMR_PERIOD_OFFSET 24
51#define SSC_RCMR_START_SIZE 4
52#define SSC_RCMR_START_OFFSET 8
53#define SSC_RCMR_STOP_SIZE 1
54#define SSC_RCMR_STOP_OFFSET 12
55#define SSC_RCMR_STTDLY_SIZE 8
56#define SSC_RCMR_STTDLY_OFFSET 16
57
58/* SSC Receive Frame Mode Register */
59#define SSC_RFMR 0x00000014
60#define SSC_RFMR_DATLEN_SIZE 5
61#define SSC_RFMR_DATLEN_OFFSET 0
62#define SSC_RFMR_DATNB_SIZE 4
63#define SSC_RFMR_DATNB_OFFSET 8
64#define SSC_RFMR_FSEDGE_SIZE 1
65#define SSC_RFMR_FSEDGE_OFFSET 24
66#define SSC_RFMR_FSLEN_SIZE 4
67#define SSC_RFMR_FSLEN_OFFSET 16
68#define SSC_RFMR_FSOS_SIZE 4
69#define SSC_RFMR_FSOS_OFFSET 20
70#define SSC_RFMR_LOOP_SIZE 1
71#define SSC_RFMR_LOOP_OFFSET 5
72#define SSC_RFMR_MSBF_SIZE 1
73#define SSC_RFMR_MSBF_OFFSET 7
74
75/* SSC Transmit Clock Mode Register */
76#define SSC_TCMR 0x00000018
77#define SSC_TCMR_CKG_SIZE 2
78#define SSC_TCMR_CKG_OFFSET 6
79#define SSC_TCMR_CKI_SIZE 1
80#define SSC_TCMR_CKI_OFFSET 5
81#define SSC_TCMR_CKO_SIZE 3
82#define SSC_TCMR_CKO_OFFSET 2
83#define SSC_TCMR_CKS_SIZE 2
84#define SSC_TCMR_CKS_OFFSET 0
85#define SSC_TCMR_PERIOD_SIZE 8
86#define SSC_TCMR_PERIOD_OFFSET 24
87#define SSC_TCMR_START_SIZE 4
88#define SSC_TCMR_START_OFFSET 8
89#define SSC_TCMR_STTDLY_SIZE 8
90#define SSC_TCMR_STTDLY_OFFSET 16
91
92/* SSC Transmit Frame Mode Register */
93#define SSC_TFMR 0x0000001c
94#define SSC_TFMR_DATDEF_SIZE 1
95#define SSC_TFMR_DATDEF_OFFSET 5
96#define SSC_TFMR_DATLEN_SIZE 5
97#define SSC_TFMR_DATLEN_OFFSET 0
98#define SSC_TFMR_DATNB_SIZE 4
99#define SSC_TFMR_DATNB_OFFSET 8
100#define SSC_TFMR_FSDEN_SIZE 1
101#define SSC_TFMR_FSDEN_OFFSET 23
102#define SSC_TFMR_FSEDGE_SIZE 1
103#define SSC_TFMR_FSEDGE_OFFSET 24
104#define SSC_TFMR_FSLEN_SIZE 4
105#define SSC_TFMR_FSLEN_OFFSET 16
106#define SSC_TFMR_FSOS_SIZE 3
107#define SSC_TFMR_FSOS_OFFSET 20
108#define SSC_TFMR_MSBF_SIZE 1
109#define SSC_TFMR_MSBF_OFFSET 7
110
111/* SSC Receive Hold Register */
112#define SSC_RHR 0x00000020
113#define SSC_RHR_RDAT_SIZE 32
114#define SSC_RHR_RDAT_OFFSET 0
115
116/* SSC Transmit Hold Register */
117#define SSC_THR 0x00000024
118#define SSC_THR_TDAT_SIZE 32
119#define SSC_THR_TDAT_OFFSET 0
120
121/* SSC Receive Sync. Holding Register */
122#define SSC_RSHR 0x00000030
123#define SSC_RSHR_RSDAT_SIZE 16
124#define SSC_RSHR_RSDAT_OFFSET 0
125
126/* SSC Transmit Sync. Holding Register */
127#define SSC_TSHR 0x00000034
128#define SSC_TSHR_TSDAT_SIZE 16
129#define SSC_TSHR_RSDAT_OFFSET 0
130
131/* SSC Receive Compare 0 Register */
132#define SSC_RC0R 0x00000038
133#define SSC_RC0R_CP0_SIZE 16
134#define SSC_RC0R_CP0_OFFSET 0
135
136/* SSC Receive Compare 1 Register */
137#define SSC_RC1R 0x0000003c
138#define SSC_RC1R_CP1_SIZE 16
139#define SSC_RC1R_CP1_OFFSET 0
140
141/* SSC Status Register */
142#define SSC_SR 0x00000040
143#define SSC_SR_CP0_SIZE 1
144#define SSC_SR_CP0_OFFSET 8
145#define SSC_SR_CP1_SIZE 1
146#define SSC_SR_CP1_OFFSET 9
147#define SSC_SR_ENDRX_SIZE 1
148#define SSC_SR_ENDRX_OFFSET 6
149#define SSC_SR_ENDTX_SIZE 1
150#define SSC_SR_ENDTX_OFFSET 2
151#define SSC_SR_OVRUN_SIZE 1
152#define SSC_SR_OVRUN_OFFSET 5
153#define SSC_SR_RXBUFF_SIZE 1
154#define SSC_SR_RXBUFF_OFFSET 7
155#define SSC_SR_RXEN_SIZE 1
156#define SSC_SR_RXEN_OFFSET 17
157#define SSC_SR_RXRDY_SIZE 1
158#define SSC_SR_RXRDY_OFFSET 4
159#define SSC_SR_RXSYN_SIZE 1
160#define SSC_SR_RXSYN_OFFSET 11
161#define SSC_SR_TXBUFE_SIZE 1
162#define SSC_SR_TXBUFE_OFFSET 3
163#define SSC_SR_TXEMPTY_SIZE 1
164#define SSC_SR_TXEMPTY_OFFSET 1
165#define SSC_SR_TXEN_SIZE 1
166#define SSC_SR_TXEN_OFFSET 16
167#define SSC_SR_TXRDY_SIZE 1
168#define SSC_SR_TXRDY_OFFSET 0
169#define SSC_SR_TXSYN_SIZE 1
170#define SSC_SR_TXSYN_OFFSET 10
171
172/* SSC Interrupt Enable Register */
173#define SSC_IER 0x00000044
174#define SSC_IER_CP0_SIZE 1
175#define SSC_IER_CP0_OFFSET 8
176#define SSC_IER_CP1_SIZE 1
177#define SSC_IER_CP1_OFFSET 9
178#define SSC_IER_ENDRX_SIZE 1
179#define SSC_IER_ENDRX_OFFSET 6
180#define SSC_IER_ENDTX_SIZE 1
181#define SSC_IER_ENDTX_OFFSET 2
182#define SSC_IER_OVRUN_SIZE 1
183#define SSC_IER_OVRUN_OFFSET 5
184#define SSC_IER_RXBUFF_SIZE 1
185#define SSC_IER_RXBUFF_OFFSET 7
186#define SSC_IER_RXRDY_SIZE 1
187#define SSC_IER_RXRDY_OFFSET 4
188#define SSC_IER_RXSYN_SIZE 1
189#define SSC_IER_RXSYN_OFFSET 11
190#define SSC_IER_TXBUFE_SIZE 1
191#define SSC_IER_TXBUFE_OFFSET 3
192#define SSC_IER_TXEMPTY_SIZE 1
193#define SSC_IER_TXEMPTY_OFFSET 1
194#define SSC_IER_TXRDY_SIZE 1
195#define SSC_IER_TXRDY_OFFSET 0
196#define SSC_IER_TXSYN_SIZE 1
197#define SSC_IER_TXSYN_OFFSET 10
198
199/* SSC Interrupt Disable Register */
200#define SSC_IDR 0x00000048
201#define SSC_IDR_CP0_SIZE 1
202#define SSC_IDR_CP0_OFFSET 8
203#define SSC_IDR_CP1_SIZE 1
204#define SSC_IDR_CP1_OFFSET 9
205#define SSC_IDR_ENDRX_SIZE 1
206#define SSC_IDR_ENDRX_OFFSET 6
207#define SSC_IDR_ENDTX_SIZE 1
208#define SSC_IDR_ENDTX_OFFSET 2
209#define SSC_IDR_OVRUN_SIZE 1
210#define SSC_IDR_OVRUN_OFFSET 5
211#define SSC_IDR_RXBUFF_SIZE 1
212#define SSC_IDR_RXBUFF_OFFSET 7
213#define SSC_IDR_RXRDY_SIZE 1
214#define SSC_IDR_RXRDY_OFFSET 4
215#define SSC_IDR_RXSYN_SIZE 1
216#define SSC_IDR_RXSYN_OFFSET 11
217#define SSC_IDR_TXBUFE_SIZE 1
218#define SSC_IDR_TXBUFE_OFFSET 3
219#define SSC_IDR_TXEMPTY_SIZE 1
220#define SSC_IDR_TXEMPTY_OFFSET 1
221#define SSC_IDR_TXRDY_SIZE 1
222#define SSC_IDR_TXRDY_OFFSET 0
223#define SSC_IDR_TXSYN_SIZE 1
224#define SSC_IDR_TXSYN_OFFSET 10
225
226/* SSC Interrupt Mask Register */
227#define SSC_IMR 0x0000004c
228#define SSC_IMR_CP0_SIZE 1
229#define SSC_IMR_CP0_OFFSET 8
230#define SSC_IMR_CP1_SIZE 1
231#define SSC_IMR_CP1_OFFSET 9
232#define SSC_IMR_ENDRX_SIZE 1
233#define SSC_IMR_ENDRX_OFFSET 6
234#define SSC_IMR_ENDTX_SIZE 1
235#define SSC_IMR_ENDTX_OFFSET 2
236#define SSC_IMR_OVRUN_SIZE 1
237#define SSC_IMR_OVRUN_OFFSET 5
238#define SSC_IMR_RXBUFF_SIZE 1
239#define SSC_IMR_RXBUFF_OFFSET 7
240#define SSC_IMR_RXRDY_SIZE 1
241#define SSC_IMR_RXRDY_OFFSET 4
242#define SSC_IMR_RXSYN_SIZE 1
243#define SSC_IMR_RXSYN_OFFSET 11
244#define SSC_IMR_TXBUFE_SIZE 1
245#define SSC_IMR_TXBUFE_OFFSET 3
246#define SSC_IMR_TXEMPTY_SIZE 1
247#define SSC_IMR_TXEMPTY_OFFSET 1
248#define SSC_IMR_TXRDY_SIZE 1
249#define SSC_IMR_TXRDY_OFFSET 0
250#define SSC_IMR_TXSYN_SIZE 1
251#define SSC_IMR_TXSYN_OFFSET 10
252
253/* SSC PDC Receive Pointer Register */
254#define SSC_PDC_RPR 0x00000100
255
256/* SSC PDC Receive Counter Register */
257#define SSC_PDC_RCR 0x00000104
258
259/* SSC PDC Transmit Pointer Register */
260#define SSC_PDC_TPR 0x00000108
261
262/* SSC PDC Receive Next Pointer Register */
263#define SSC_PDC_RNPR 0x00000110
264
265/* SSC PDC Receive Next Counter Register */
266#define SSC_PDC_RNCR 0x00000114
267
268/* SSC PDC Transmit Counter Register */
269#define SSC_PDC_TCR 0x0000010c
270
271/* SSC PDC Transmit Next Pointer Register */
272#define SSC_PDC_TNPR 0x00000118
273
274/* SSC PDC Transmit Next Counter Register */
275#define SSC_PDC_TNCR 0x0000011c
276
277/* SSC PDC Transfer Control Register */
278#define SSC_PDC_PTCR 0x00000120
279#define SSC_PDC_PTCR_RXTDIS_SIZE 1
280#define SSC_PDC_PTCR_RXTDIS_OFFSET 1
281#define SSC_PDC_PTCR_RXTEN_SIZE 1
282#define SSC_PDC_PTCR_RXTEN_OFFSET 0
283#define SSC_PDC_PTCR_TXTDIS_SIZE 1
284#define SSC_PDC_PTCR_TXTDIS_OFFSET 9
285#define SSC_PDC_PTCR_TXTEN_SIZE 1
286#define SSC_PDC_PTCR_TXTEN_OFFSET 8
287
288/* SSC PDC Transfer Status Register */
289#define SSC_PDC_PTSR 0x00000124
290#define SSC_PDC_PTSR_RXTEN_SIZE 1
291#define SSC_PDC_PTSR_RXTEN_OFFSET 0
292#define SSC_PDC_PTSR_TXTEN_SIZE 1
293#define SSC_PDC_PTSR_TXTEN_OFFSET 8
294
295/* Bit manipulation macros */
296#define SSC_BIT(name) \
297 (1 << SSC_##name##_OFFSET)
298#define SSC_BF(name, value) \
299 (((value) & ((1 << SSC_##name##_SIZE) - 1)) \
300 << SSC_##name##_OFFSET)
301#define SSC_BFEXT(name, value) \
302 (((value) >> SSC_##name##_OFFSET) \
303 & ((1 << SSC_##name##_SIZE) - 1))
304#define SSC_BFINS(name, value, old) \
305 (((old) & ~(((1 << SSC_##name##_SIZE) - 1) \
306 << SSC_##name##_OFFSET)) | SSC_BF(name, value))
307
308/* Register access macros */
309#define ssc_readl(base, reg) __raw_readl(base + SSC_##reg)
310#define ssc_writel(base, reg, value) __raw_writel((value), base + SSC_##reg)
311
312#endif /* __INCLUDE_ATMEL_SSC_H */