diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-12-01 23:34:58 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-12-01 23:34:58 -0500 |
commit | 3bc324922663bda59af5cdc409e8df3ed217d296 (patch) | |
tree | 1c9c7d527c4fd3383350d54acd7d15b9c5c4f639 /drivers | |
parent | 9d3493e84def26bd9b0bab825629063bacc89383 (diff) | |
parent | 3951e4aae2ce7e4593e575e91cbb22f1ba153596 (diff) |
Merge remote-tracking branch 'asoc/topic/atmel' into asoc-next
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/atmel-ssc.c | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb187781074..d07a9eda7fff 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | 20 | ||
21 | #include <linux/of.h> | ||
22 | |||
21 | /* Serialize access to ssc_list and user count */ | 23 | /* Serialize access to ssc_list and user count */ |
22 | static DEFINE_SPINLOCK(user_lock); | 24 | static DEFINE_SPINLOCK(user_lock); |
23 | static LIST_HEAD(ssc_list); | 25 | static LIST_HEAD(ssc_list); |
@@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num) | |||
29 | 31 | ||
30 | spin_lock(&user_lock); | 32 | spin_lock(&user_lock); |
31 | list_for_each_entry(ssc, &ssc_list, list) { | 33 | list_for_each_entry(ssc, &ssc_list, list) { |
32 | if (ssc->pdev->id == ssc_num) { | 34 | if (ssc->pdev->dev.of_node) { |
35 | if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc") | ||
36 | == ssc_num) { | ||
37 | ssc_valid = 1; | ||
38 | break; | ||
39 | } | ||
40 | } else if (ssc->pdev->id == ssc_num) { | ||
33 | ssc_valid = 1; | 41 | ssc_valid = 1; |
34 | break; | 42 | break; |
35 | } | 43 | } |
@@ -68,39 +76,93 @@ void ssc_free(struct ssc_device *ssc) | |||
68 | } | 76 | } |
69 | EXPORT_SYMBOL(ssc_free); | 77 | EXPORT_SYMBOL(ssc_free); |
70 | 78 | ||
71 | static int __init ssc_probe(struct platform_device *pdev) | 79 | static struct atmel_ssc_platform_data at91rm9200_config = { |
80 | .use_dma = 0, | ||
81 | }; | ||
82 | |||
83 | static struct atmel_ssc_platform_data at91sam9g45_config = { | ||
84 | .use_dma = 1, | ||
85 | }; | ||
86 | |||
87 | static const struct platform_device_id atmel_ssc_devtypes[] = { | ||
88 | { | ||
89 | .name = "at91rm9200_ssc", | ||
90 | .driver_data = (unsigned long) &at91rm9200_config, | ||
91 | }, { | ||
92 | .name = "at91sam9g45_ssc", | ||
93 | .driver_data = (unsigned long) &at91sam9g45_config, | ||
94 | }, { | ||
95 | /* sentinel */ | ||
96 | } | ||
97 | }; | ||
98 | |||
99 | #ifdef CONFIG_OF | ||
100 | static const struct of_device_id atmel_ssc_dt_ids[] = { | ||
101 | { | ||
102 | .compatible = "atmel,at91rm9200-ssc", | ||
103 | .data = &at91rm9200_config, | ||
104 | }, { | ||
105 | .compatible = "atmel,at91sam9g45-ssc", | ||
106 | .data = &at91sam9g45_config, | ||
107 | }, { | ||
108 | /* sentinel */ | ||
109 | } | ||
110 | }; | ||
111 | MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids); | ||
112 | #endif | ||
113 | |||
114 | static inline const struct atmel_ssc_platform_data * __init | ||
115 | atmel_ssc_get_driver_data(struct platform_device *pdev) | ||
116 | { | ||
117 | if (pdev->dev.of_node) { | ||
118 | const struct of_device_id *match; | ||
119 | match = of_match_node(atmel_ssc_dt_ids, pdev->dev.of_node); | ||
120 | if (match == NULL) | ||
121 | return NULL; | ||
122 | return match->data; | ||
123 | } | ||
124 | |||
125 | return (struct atmel_ssc_platform_data *) | ||
126 | platform_get_device_id(pdev)->driver_data; | ||
127 | } | ||
128 | |||
129 | static int ssc_probe(struct platform_device *pdev) | ||
72 | { | 130 | { |
73 | int retval = 0; | ||
74 | struct resource *regs; | 131 | struct resource *regs; |
75 | struct ssc_device *ssc; | 132 | struct ssc_device *ssc; |
133 | const struct atmel_ssc_platform_data *plat_dat; | ||
76 | 134 | ||
77 | ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL); | 135 | ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); |
78 | if (!ssc) { | 136 | if (!ssc) { |
79 | dev_dbg(&pdev->dev, "out of memory\n"); | 137 | dev_dbg(&pdev->dev, "out of memory\n"); |
80 | retval = -ENOMEM; | 138 | return -ENOMEM; |
81 | goto out; | ||
82 | } | 139 | } |
83 | 140 | ||
141 | ssc->pdev = pdev; | ||
142 | |||
143 | plat_dat = atmel_ssc_get_driver_data(pdev); | ||
144 | if (!plat_dat) | ||
145 | return -ENODEV; | ||
146 | ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat; | ||
147 | |||
84 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 148 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
85 | if (!regs) { | 149 | if (!regs) { |
86 | dev_dbg(&pdev->dev, "no mmio resource defined\n"); | 150 | dev_dbg(&pdev->dev, "no mmio resource defined\n"); |
87 | retval = -ENXIO; | 151 | return -ENXIO; |
88 | goto out_free; | ||
89 | } | 152 | } |
90 | 153 | ||
91 | ssc->clk = clk_get(&pdev->dev, "pclk"); | 154 | ssc->regs = devm_request_and_ioremap(&pdev->dev, regs); |
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) { | 155 | if (!ssc->regs) { |
101 | dev_dbg(&pdev->dev, "ioremap failed\n"); | 156 | dev_dbg(&pdev->dev, "ioremap failed\n"); |
102 | retval = -EINVAL; | 157 | return -EINVAL; |
103 | goto out_clk; | 158 | } |
159 | |||
160 | ssc->phybase = regs->start; | ||
161 | |||
162 | ssc->clk = devm_clk_get(&pdev->dev, "pclk"); | ||
163 | if (IS_ERR(ssc->clk)) { | ||
164 | dev_dbg(&pdev->dev, "no pclk clock defined\n"); | ||
165 | return -ENXIO; | ||
104 | } | 166 | } |
105 | 167 | ||
106 | /* disable all interrupts */ | 168 | /* disable all interrupts */ |
@@ -112,8 +174,7 @@ static int __init ssc_probe(struct platform_device *pdev) | |||
112 | ssc->irq = platform_get_irq(pdev, 0); | 174 | ssc->irq = platform_get_irq(pdev, 0); |
113 | if (!ssc->irq) { | 175 | if (!ssc->irq) { |
114 | dev_dbg(&pdev->dev, "could not get irq\n"); | 176 | dev_dbg(&pdev->dev, "could not get irq\n"); |
115 | retval = -ENXIO; | 177 | return -ENXIO; |
116 | goto out_unmap; | ||
117 | } | 178 | } |
118 | 179 | ||
119 | spin_lock(&user_lock); | 180 | spin_lock(&user_lock); |
@@ -125,16 +186,7 @@ static int __init ssc_probe(struct platform_device *pdev) | |||
125 | dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n", | 186 | dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n", |
126 | ssc->regs, ssc->irq); | 187 | ssc->regs, ssc->irq); |
127 | 188 | ||
128 | goto out; | 189 | return 0; |
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 | } | 190 | } |
139 | 191 | ||
140 | static int __devexit ssc_remove(struct platform_device *pdev) | 192 | static int __devexit ssc_remove(struct platform_device *pdev) |
@@ -142,34 +194,23 @@ static int __devexit ssc_remove(struct platform_device *pdev) | |||
142 | struct ssc_device *ssc = platform_get_drvdata(pdev); | 194 | struct ssc_device *ssc = platform_get_drvdata(pdev); |
143 | 195 | ||
144 | spin_lock(&user_lock); | 196 | spin_lock(&user_lock); |
145 | iounmap(ssc->regs); | ||
146 | clk_put(ssc->clk); | ||
147 | list_del(&ssc->list); | 197 | list_del(&ssc->list); |
148 | kfree(ssc); | ||
149 | spin_unlock(&user_lock); | 198 | spin_unlock(&user_lock); |
150 | 199 | ||
151 | return 0; | 200 | return 0; |
152 | } | 201 | } |
153 | 202 | ||
154 | static struct platform_driver ssc_driver = { | 203 | static struct platform_driver ssc_driver = { |
155 | .remove = __devexit_p(ssc_remove), | ||
156 | .driver = { | 204 | .driver = { |
157 | .name = "ssc", | 205 | .name = "ssc", |
158 | .owner = THIS_MODULE, | 206 | .owner = THIS_MODULE, |
207 | .of_match_table = of_match_ptr(atmel_ssc_dt_ids), | ||
159 | }, | 208 | }, |
209 | .id_table = atmel_ssc_devtypes, | ||
210 | .probe = ssc_probe, | ||
211 | .remove = __devexit_p(ssc_remove), | ||
160 | }; | 212 | }; |
161 | 213 | module_platform_driver(ssc_driver); | |
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 | 214 | ||
174 | MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); | 215 | MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); |
175 | MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91"); | 216 | MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91"); |