diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-10-25 02:53:01 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-10-25 03:11:07 -0400 |
commit | a4d6983c7a164c39bc0289124a2cd9f765d333d0 (patch) | |
tree | 1ce6911712a3cd161670f5b0757557a453f80ca9 /drivers/input/serio | |
parent | e4b290094603423623d3f268e054f40f3f51afa8 (diff) |
Input: arc_ps2 - switch to using managed resources
Using managed resources simplifies error handling and shrinks
size of arc_ps2_remove().
Tested-by: Mischa Jonker <mischa.jonker@synopsys.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/serio')
-rw-r--r-- | drivers/input/serio/arc_ps2.c | 123 |
1 files changed, 59 insertions, 64 deletions
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index f8c026ac15e1..89ad7631848e 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c | |||
@@ -38,8 +38,6 @@ struct arc_ps2_port { | |||
38 | 38 | ||
39 | struct arc_ps2_data { | 39 | struct arc_ps2_data { |
40 | struct arc_ps2_port port[ARC_PS2_PORTS]; | 40 | struct arc_ps2_port port[ARC_PS2_PORTS]; |
41 | struct resource *iomem_res; | ||
42 | int irq; | ||
43 | void __iomem *addr; | 41 | void __iomem *addr; |
44 | unsigned int frame_error; | 42 | unsigned int frame_error; |
45 | unsigned int buf_overflow; | 43 | unsigned int buf_overflow; |
@@ -125,6 +123,32 @@ static void arc_ps2_close(struct serio *io) | |||
125 | port->status_addr); | 123 | port->status_addr); |
126 | } | 124 | } |
127 | 125 | ||
126 | static void __iomem * __devinit arc_ps2_calc_addr(struct arc_ps2_data *arc_ps2, | ||
127 | int index, bool status) | ||
128 | { | ||
129 | void __iomem *addr; | ||
130 | |||
131 | addr = arc_ps2->addr + 4 + 4 * index; | ||
132 | if (status) | ||
133 | addr += ARC_PS2_PORTS * 4; | ||
134 | |||
135 | return addr; | ||
136 | } | ||
137 | |||
138 | static void __devinit arc_ps2_inhibit_ports(struct arc_ps2_data *arc_ps2) | ||
139 | { | ||
140 | void __iomem *addr; | ||
141 | u32 val; | ||
142 | int i; | ||
143 | |||
144 | for (i = 0; i < ARC_PS2_PORTS; i++) { | ||
145 | addr = arc_ps2_calc_addr(arc_ps2, i, true); | ||
146 | val = ioread32(addr); | ||
147 | val &= ~(PS2_STAT_RX_INT_EN | PS2_STAT_TX_INT_EN); | ||
148 | iowrite32(val, addr); | ||
149 | } | ||
150 | } | ||
151 | |||
128 | static int __devinit arc_ps2_create_port(struct platform_device *pdev, | 152 | static int __devinit arc_ps2_create_port(struct platform_device *pdev, |
129 | struct arc_ps2_data *arc_ps2, | 153 | struct arc_ps2_data *arc_ps2, |
130 | int index) | 154 | int index) |
@@ -146,8 +170,8 @@ static int __devinit arc_ps2_create_port(struct platform_device *pdev, | |||
146 | 170 | ||
147 | port->io = io; | 171 | port->io = io; |
148 | 172 | ||
149 | port->data_addr = arc_ps2->addr + 4 + index * 4; | 173 | port->data_addr = arc_ps2_calc_addr(arc_ps2, index, false); |
150 | port->status_addr = arc_ps2->addr + 4 + ARC_PS2_PORTS * 4 + index * 4; | 174 | port->status_addr = arc_ps2_calc_addr(arc_ps2, index, true); |
151 | 175 | ||
152 | dev_dbg(&pdev->dev, "port%d is allocated (data = 0x%p, status = 0x%p)\n", | 176 | dev_dbg(&pdev->dev, "port%d is allocated (data = 0x%p, status = 0x%p)\n", |
153 | index, port->data_addr, port->status_addr); | 177 | index, port->data_addr, port->status_addr); |
@@ -159,85 +183,63 @@ static int __devinit arc_ps2_create_port(struct platform_device *pdev, | |||
159 | static int __devinit arc_ps2_probe(struct platform_device *pdev) | 183 | static int __devinit arc_ps2_probe(struct platform_device *pdev) |
160 | { | 184 | { |
161 | struct arc_ps2_data *arc_ps2; | 185 | struct arc_ps2_data *arc_ps2; |
186 | struct resource *res; | ||
187 | int irq; | ||
162 | int error, id, i; | 188 | int error, id, i; |
163 | 189 | ||
164 | arc_ps2 = kzalloc(sizeof(struct arc_ps2_data), GFP_KERNEL); | 190 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
165 | if (!arc_ps2) { | 191 | if (!res) { |
166 | dev_err(&pdev->dev, "out of memory\n"); | ||
167 | return -ENOMEM; | ||
168 | } | ||
169 | |||
170 | arc_ps2->iomem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
171 | if (!arc_ps2->iomem_res) { | ||
172 | dev_err(&pdev->dev, "no IO memory defined\n"); | 192 | dev_err(&pdev->dev, "no IO memory defined\n"); |
173 | error = -EINVAL; | 193 | return -EINVAL; |
174 | goto err_free_mem; | ||
175 | } | 194 | } |
176 | 195 | ||
177 | arc_ps2->irq = platform_get_irq_byname(pdev, "arc_ps2_irq"); | 196 | irq = platform_get_irq_byname(pdev, "arc_ps2_irq"); |
178 | if (arc_ps2->irq < 0) { | 197 | if (irq < 0) { |
179 | dev_err(&pdev->dev, "no IRQ defined\n"); | 198 | dev_err(&pdev->dev, "no IRQ defined\n"); |
180 | error = -EINVAL; | 199 | return -EINVAL; |
181 | goto err_free_mem; | ||
182 | } | 200 | } |
183 | 201 | ||
184 | if (!request_mem_region(arc_ps2->iomem_res->start, | 202 | arc_ps2 = devm_kzalloc(&pdev->dev, sizeof(struct arc_ps2_data), |
185 | resource_size(arc_ps2->iomem_res), pdev->name)) { | 203 | GFP_KERNEL); |
186 | dev_err(&pdev->dev, "memory region allocation failed for %pR\n", | 204 | if (!arc_ps2) { |
187 | arc_ps2->iomem_res); | 205 | dev_err(&pdev->dev, "out of memory\n"); |
188 | 206 | return -ENOMEM; | |
189 | error = -EBUSY; | ||
190 | goto err_free_mem; | ||
191 | } | 207 | } |
192 | 208 | ||
193 | arc_ps2->addr = ioremap_nocache(arc_ps2->iomem_res->start, | 209 | arc_ps2->addr = devm_request_and_ioremap(&pdev->dev, res); |
194 | resource_size(arc_ps2->iomem_res)); | 210 | if (!arc_ps2->addr) |
195 | if (!arc_ps2->addr) { | 211 | return -EBUSY; |
196 | dev_err(&pdev->dev, "memory mapping failed\n"); | ||
197 | error = -ENOMEM; | ||
198 | goto err_release_region; | ||
199 | } | ||
200 | 212 | ||
201 | dev_info(&pdev->dev, "irq = %d, address = 0x%p, ports = %i\n", | 213 | dev_info(&pdev->dev, "irq = %d, address = 0x%p, ports = %i\n", |
202 | arc_ps2->irq, arc_ps2->addr, ARC_PS2_PORTS); | 214 | irq, arc_ps2->addr, ARC_PS2_PORTS); |
203 | 215 | ||
204 | id = ioread32(arc_ps2->addr); | 216 | id = ioread32(arc_ps2->addr); |
205 | if (id != ARC_ARC_PS2_ID) { | 217 | if (id != ARC_ARC_PS2_ID) { |
206 | dev_err(&pdev->dev, "device id does not match\n"); | 218 | dev_err(&pdev->dev, "device id does not match\n"); |
207 | error = -ENXIO; | 219 | return -ENXIO; |
208 | goto err_unmap; | ||
209 | } | 220 | } |
210 | 221 | ||
211 | for (i = 0; i < ARC_PS2_PORTS; i++) { | 222 | arc_ps2_inhibit_ports(arc_ps2); |
212 | error = arc_ps2_create_port(pdev, arc_ps2, i); | ||
213 | if (error) | ||
214 | goto err_unregister_ports; | ||
215 | } | ||
216 | 223 | ||
217 | error = request_irq(arc_ps2->irq, arc_ps2_interrupt, 0, | 224 | error = devm_request_irq(&pdev->dev, irq, arc_ps2_interrupt, |
218 | "arc_ps2", arc_ps2); | 225 | 0, "arc_ps2", arc_ps2); |
219 | if (error) { | 226 | if (error) { |
220 | dev_err(&pdev->dev, "Could not allocate IRQ\n"); | 227 | dev_err(&pdev->dev, "Could not allocate IRQ\n"); |
221 | goto err_unregister_ports; | 228 | return error; |
229 | } | ||
230 | |||
231 | for (i = 0; i < ARC_PS2_PORTS; i++) { | ||
232 | error = arc_ps2_create_port(pdev, arc_ps2, i); | ||
233 | if (error) { | ||
234 | while (--i >= 0) | ||
235 | serio_unregister_port(arc_ps2->port[i].io); | ||
236 | return error; | ||
237 | } | ||
222 | } | 238 | } |
223 | 239 | ||
224 | platform_set_drvdata(pdev, arc_ps2); | 240 | platform_set_drvdata(pdev, arc_ps2); |
225 | 241 | ||
226 | return 0; | 242 | return 0; |
227 | |||
228 | err_unregister_ports: | ||
229 | for (i = 0; i < ARC_PS2_PORTS; i++) { | ||
230 | if (arc_ps2->port[i].io) | ||
231 | serio_unregister_port(arc_ps2->port[i].io); | ||
232 | } | ||
233 | err_unmap: | ||
234 | iounmap(arc_ps2->addr); | ||
235 | err_release_region: | ||
236 | release_mem_region(arc_ps2->iomem_res->start, | ||
237 | resource_size(arc_ps2->iomem_res)); | ||
238 | err_free_mem: | ||
239 | kfree(arc_ps2); | ||
240 | return error; | ||
241 | } | 243 | } |
242 | 244 | ||
243 | static int __devexit arc_ps2_remove(struct platform_device *pdev) | 245 | static int __devexit arc_ps2_remove(struct platform_device *pdev) |
@@ -248,18 +250,11 @@ static int __devexit arc_ps2_remove(struct platform_device *pdev) | |||
248 | for (i = 0; i < ARC_PS2_PORTS; i++) | 250 | for (i = 0; i < ARC_PS2_PORTS; i++) |
249 | serio_unregister_port(arc_ps2->port[i].io); | 251 | serio_unregister_port(arc_ps2->port[i].io); |
250 | 252 | ||
251 | free_irq(arc_ps2->irq, arc_ps2); | ||
252 | iounmap(arc_ps2->addr); | ||
253 | release_mem_region(arc_ps2->iomem_res->start, | ||
254 | resource_size(arc_ps2->iomem_res)); | ||
255 | |||
256 | dev_dbg(&pdev->dev, "interrupt count = %i\n", arc_ps2->total_int); | 253 | dev_dbg(&pdev->dev, "interrupt count = %i\n", arc_ps2->total_int); |
257 | dev_dbg(&pdev->dev, "frame error count = %i\n", arc_ps2->frame_error); | 254 | dev_dbg(&pdev->dev, "frame error count = %i\n", arc_ps2->frame_error); |
258 | dev_dbg(&pdev->dev, "buffer overflow count = %i\n", | 255 | dev_dbg(&pdev->dev, "buffer overflow count = %i\n", |
259 | arc_ps2->buf_overflow); | 256 | arc_ps2->buf_overflow); |
260 | 257 | ||
261 | kfree(arc_ps2); | ||
262 | |||
263 | return 0; | 258 | return 0; |
264 | } | 259 | } |
265 | 260 | ||