Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
atmel-ssc.c
Go to the documentation of this file.
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 #include <linux/module.h>
20 
21 /* Serialize access to ssc_list and user count */
22 static DEFINE_SPINLOCK(user_lock);
23 static LIST_HEAD(ssc_list);
24 
25 struct ssc_device *ssc_request(unsigned int ssc_num)
26 {
27  int ssc_valid = 0;
28  struct ssc_device *ssc;
29 
30  spin_lock(&user_lock);
31  list_for_each_entry(ssc, &ssc_list, list) {
32  if (ssc->pdev->id == ssc_num) {
33  ssc_valid = 1;
34  break;
35  }
36  }
37 
38  if (!ssc_valid) {
39  spin_unlock(&user_lock);
40  pr_err("ssc: ssc%d platform device is missing\n", ssc_num);
41  return ERR_PTR(-ENODEV);
42  }
43 
44  if (ssc->user) {
45  spin_unlock(&user_lock);
46  dev_dbg(&ssc->pdev->dev, "module busy\n");
47  return ERR_PTR(-EBUSY);
48  }
49  ssc->user++;
50  spin_unlock(&user_lock);
51 
52  clk_enable(ssc->clk);
53 
54  return ssc;
55 }
57 
58 void ssc_free(struct ssc_device *ssc)
59 {
60  spin_lock(&user_lock);
61  if (ssc->user) {
62  ssc->user--;
63  clk_disable(ssc->clk);
64  } else {
65  dev_dbg(&ssc->pdev->dev, "device already free\n");
66  }
67  spin_unlock(&user_lock);
68 }
70 
71 static int __init ssc_probe(struct platform_device *pdev)
72 {
73  int retval = 0;
74  struct resource *regs;
75  struct ssc_device *ssc;
76 
77  ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL);
78  if (!ssc) {
79  dev_dbg(&pdev->dev, "out of memory\n");
80  retval = -ENOMEM;
81  goto out;
82  }
83 
84  regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
85  if (!regs) {
86  dev_dbg(&pdev->dev, "no mmio resource defined\n");
87  retval = -ENXIO;
88  goto out_free;
89  }
90 
91  ssc->clk = clk_get(&pdev->dev, "pclk");
92  if (IS_ERR(ssc->clk)) {
93  dev_dbg(&pdev->dev, "no pclk clock defined\n");
94  retval = -ENXIO;
95  goto out_free;
96  }
97 
98  ssc->pdev = pdev;
99  ssc->regs = ioremap(regs->start, resource_size(regs));
100  if (!ssc->regs) {
101  dev_dbg(&pdev->dev, "ioremap failed\n");
102  retval = -EINVAL;
103  goto out_clk;
104  }
105 
106  /* disable all interrupts */
107  clk_enable(ssc->clk);
108  ssc_writel(ssc->regs, IDR, ~0UL);
109  ssc_readl(ssc->regs, SR);
110  clk_disable(ssc->clk);
111 
112  ssc->irq = platform_get_irq(pdev, 0);
113  if (!ssc->irq) {
114  dev_dbg(&pdev->dev, "could not get irq\n");
115  retval = -ENXIO;
116  goto out_unmap;
117  }
118 
119  spin_lock(&user_lock);
120  list_add_tail(&ssc->list, &ssc_list);
121  spin_unlock(&user_lock);
122 
123  platform_set_drvdata(pdev, ssc);
124 
125  dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
126  ssc->regs, ssc->irq);
127 
128  goto out;
129 
130 out_unmap:
131  iounmap(ssc->regs);
132 out_clk:
133  clk_put(ssc->clk);
134 out_free:
135  kfree(ssc);
136 out:
137  return retval;
138 }
139 
140 static int __devexit ssc_remove(struct platform_device *pdev)
141 {
142  struct ssc_device *ssc = platform_get_drvdata(pdev);
143 
144  spin_lock(&user_lock);
145  iounmap(ssc->regs);
146  clk_put(ssc->clk);
147  list_del(&ssc->list);
148  kfree(ssc);
149  spin_unlock(&user_lock);
150 
151  return 0;
152 }
153 
154 static struct platform_driver ssc_driver = {
155  .remove = __devexit_p(ssc_remove),
156  .driver = {
157  .name = "ssc",
158  .owner = THIS_MODULE,
159  },
160 };
161 
162 static int __init ssc_init(void)
163 {
164  return platform_driver_probe(&ssc_driver, ssc_probe);
165 }
166 module_init(ssc_init);
167 
168 static void __exit ssc_exit(void)
169 {
170  platform_driver_unregister(&ssc_driver);
171 }
172 module_exit(ssc_exit);
173 
174 MODULE_AUTHOR("Hans-Christian Egtvedt <[email protected]>");
175 MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91");
176 MODULE_LICENSE("GPL");
177 MODULE_ALIAS("platform:ssc");